无法在 UWP 中创建 CompositionTarget
Can't create a CompositionTarget in UWP
我正在使用通过
提取的CreateTargetForCurrentView API by invoking it on a UIElement's Compositor对象
auto visual = ElementCompositionPreview::GetElementVisual(elem);
auto compositor = visual->Compositor;
在此之后,因为我想创建一棵 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 树来承载这棵视觉树。
auto containerVisual = compositor->CreateContainerVisual();
现在因为这个 ContainerVisual
需要附加到 CompositionTarget 的 root
,我这样做了(参考 here):
auto compositionTarget = compositor->CreateTargetForCurrentView();
但这会导致 DCOMPOSITION_ERROR_WINDOW_ALREADY_COMPOSED
,根据 docs 暗示:
The IDCompositionDevice::CreateTargetForHwnd method was called with
hwnd and topmost parameters for which a visual tree already exists.
如果我没理解错的话,意思是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
的方法,但文档显然已经过时了。
如果要在XAML和Visual Layer之间互操作,我们不应该纠缠在CompositionTarget
。让我们回到如何使用 ContainerVisual
创建可视化树。
请参阅 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,展示如何从 UIElement
抓取视觉对象并将视觉对象设置为 UIElement
。
您可以参考以下示例代码:
添加命名空间和 header:
#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();
获取视觉对象和设置视觉对象的代码:
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;
}
我正在使用通过
提取的CreateTargetForCurrentView API by invoking it on a UIElement's Compositor对象auto visual = ElementCompositionPreview::GetElementVisual(elem);
auto compositor = visual->Compositor;
在此之后,因为我想创建一棵 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 树来承载这棵视觉树。
auto containerVisual = compositor->CreateContainerVisual();
现在因为这个 ContainerVisual
需要附加到 CompositionTarget 的 root
,我这样做了(参考 here):
auto compositionTarget = compositor->CreateTargetForCurrentView();
但这会导致 DCOMPOSITION_ERROR_WINDOW_ALREADY_COMPOSED
,根据 docs 暗示:
The IDCompositionDevice::CreateTargetForHwnd method was called with hwnd and topmost parameters for which a visual tree already exists.
如果我没理解错的话,意思是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
的方法,但文档显然已经过时了。
如果要在XAML和Visual Layer之间互操作,我们不应该纠缠在CompositionTarget
。让我们回到如何使用 ContainerVisual
创建可视化树。
请参阅 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,展示如何从 UIElement
抓取视觉对象并将视觉对象设置为 UIElement
。
您可以参考以下示例代码:
添加命名空间和 header:
#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();
获取视觉对象和设置视觉对象的代码:
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;
}