无法在 UWP 中创建 CompositionTarget [英] Can't create a CompositionTarget in UWP
问题描述
我使用的是 CreateTargetForCurrentView API 通过在 UIElement 的 合成器对象通过
I was using the CreateTargetForCurrentView API by invoking it on a UIElement's Compositor object extracted via
auto visual = ElementCompositionPreview::GetElementVisual(elem);
auto compositor = visual->Compositor;
在此之后,因为我想创建一棵树 视觉 s 之间有一种排序感,以便我可以根据我的用例将视觉放在另一个之上,我创建了一个 ContainerVisual 来托管这个视觉树.
After this, since I want to create a tree of Visuals with a sense of ordering amongst them so that I can position the visual one above the other as per my use case, I created a ContainerVisual to host this tree of visuals.
auto containerVisual = compositor->CreateContainerVisual();
现在由于这个 ContainerVisual
需要附加到 CompositionTarget 的 root
,我这样做了(从 此处):
Now since this ContainerVisual
needs to be attached to the root
of a CompositionTarget, I did so (taking the reference from here):
auto compositionTarget = compositor->CreateTargetForCurrentView();
但这会导致 DCOMPOSITION_ERROR_WINDOW_ALREADY_COMPOSED
根据 docs 暗示:
but this leads to a DCOMPOSITION_ERROR_WINDOW_ALREADY_COMPOSED
which as per the docs implies:
IDCompositionDevice::CreateTargetForHwnd 方法被调用已存在可视化树的 hwnd 和最顶层参数.
The IDCompositionDevice::CreateTargetForHwnd method was called with hwnd and topmost parameters for which a visual tree already exists.
如果我理解正确,这意味着 IDCompositionDevice::CreateTargetForHwnd 在我的 UWP 应用程序的生命周期中以某种方式被调用.此 API 是一个 Win32
API,未直接在应用程序中使用.现在我的问题是,在 UWP 应用程序中,Windows.UI.Composition
命名空间下的什么 API 或任何其他 API,在 C++/Cx
投影下,我应该寻找那个可能在内部调用导致此异常的 IDCompositionDevice::CreateTargetForHwnd
?或者更好的是,是否有任何 API 可用于从 View
或 Window
中提取 CompositionTarget
?我看到 CoreApplicationView
类中有一个属性 CompositionRootVisual
可用于直接附加 ContainerVisual
但它在其中一个中被删除API 更新按照 this.
If I understand correctly, this means IDCompositionDevice::CreateTargetForHwnd has been called somehow during the lifecycle of my UWP app. This API is a Win32
API that isn't being used directly in the app. Now my question is, in a UWP app, what API under Windows.UI.Composition
namespace or any other, under the C++/Cx
projection, should I be looking for that might be internally invoking IDCompositionDevice::CreateTargetForHwnd
that's leading to this exception? Or better still, is there any API that can be used to extract a CompositionTarget
from a View
or Window
? I see that there was a property CompositionRootVisual
in the CoreApplicationView
class that could be used to attach the ContainerVisual
directly but it was removed in one of the API updates as per this.
| public class Windows.ApplicationModel.Core.CoreApplicationView {
- public Visual CompositionRootVisual { get; set; }
| }
奇怪的是,即使是 docs 指的是将 ContainerVisual
附加到 View
的这条路线,但文档显然已经过时了.
Strangely even the docs refer to this route of attaching a ContainerVisual
to a View
but the documentation is apparently outdated.
推荐答案
如果要在 XAML 和可视层之间进行互操作,我们不应该纠结于 CompositionTarget
.让我们回到如何使用 ContainerVisual
创建可视化树.请参阅文档,我们可以使用 ElementCompositionPreview.GetElementVisual(UIElement)
方法来获取任何页面元素的背景视觉,并使用 ElementCompositionPreview.SetElementChildVisual(UIElement, Visual) 方法将创建的视觉对象一个 UIElement 的可视化树.上面的文档和本文档中有一些代码 将视觉层与 XAML 结合使用,展示了如何从 UIElement
获取视觉对象并将视觉对象设置为 UIElement
.
If you want to interop between XAML and the Visual Layer, we shouldn’t be entangled in CompositionTarget
. Let’s back to how to use ContainerVisual
to create a visual tree.
Refer to the document, we could use ElementCompositionPreview.GetElementVisual(UIElement)
method to grab the backing visual for any page element, and use ElementCompositionPreview.SetElementChildVisual(UIElement, Visual) method to take a created visual to a UIElement’s visual tree. There are some code in the above document and this document Using the Visual Layer with XAML, showing how to grab a visual from a UIElement
and set a visual to a UIElement
.
以下是您可以参考的示例代码:
Here is the sample code you could refer to:
添加命名空间和标题:
#include "windowsnumerics.h"
using namespace Windows::UI::Xaml::Hosting;
using namespace Windows::UI::Composition;
using namespace Windows::Foundation::Numerics;
using namespace Windows::UI;
声明一些成员:
private:
Compositor^ _compositor;
ContainerVisual^ _root;
Visual^ CreateChildElement();
抓取视觉对象和设置视觉对象的代码:
The code to grab a visual and set a visual:
void App2::MainPage::Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
_compositor = ElementCompositionPreview::GetElementVisual(this)->Compositor;
_root = _compositor->CreateContainerVisual();
for (int i = 0; i < 5; i++)
{
_root->Children->InsertAtTop(CreateChildElement());
}
ElementCompositionPreview::SetElementChildVisual(this, _root);
}
Visual^ App2::MainPage::CreateChildElement()
{
auto element = _compositor->CreateContainerVisual();
element->Size = float2(100.0f, 100.0f);
//
// Position this visual randomly within our window
//
element->Offset = float3(((float)rand() / RAND_MAX) * 400, ((float)rand() / RAND_MAX) * 400, 0.0f);
//
// The outer rectangle is always white
//
auto visual = _compositor->CreateSpriteVisual();
element->Children->InsertAtTop(visual);
visual->Brush = _compositor->CreateColorBrush(ColorHelper::FromArgb(0xFF, 0xFF, 0x11, 0xFF));
visual->Size = float2(100.0f, 100.0f);
//
// The inner rectangle is inset from the outer by three pixels all around
//
auto child = _compositor->CreateSpriteVisual();
visual->Children->InsertAtTop(child);
child->Offset = float3(3.0f, 3.0f, 0.0f);
child->Size = float2(94.0f, 94.0f);
//
// Pick a random color for every rectangle
//
byte red = (byte)(0xFF * (0.2f + (((float)rand()/RAND_MAX) / 0.8f)));
byte green = (byte)(0xFF * (0.2f + (((float)rand() / RAND_MAX) / 0.8f)));
byte blue = (byte)(0xFF * (0.2f + (((float)rand() / RAND_MAX) / 0.8f)));
child->Brush = _compositor->CreateColorBrush(ColorHelper::FromArgb(0xFF, red, green, blue));
//
// Make the subtree root visual partially transparent. This will cause each visual in the subtree
// to render partially transparent, since a visual's opacity is multiplied with its parent's
// opacity
//
element->Opacity = 0.8f;
return element;
}
这篇关于无法在 UWP 中创建 CompositionTarget的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!