如何在代码中创建XAML自定义控件?

时间:2018-06-12 19:52:49

标签: uwp c++-winrt

我正在尝试使用C ++ / WinRT在代码中实现自定义XAML控件。但是,我尝试的实现无法编译。作为概念的证明,我使用了这段代码:

#pragma once

#include <winrt/Windows.UI.Xaml.Controls.h>

namespace MyApp
{
    struct MyControl : winrt::implements<MyControl, winrt::Windows::UI::Xaml::Controls::Control>
    {
    };
}

这导致以下编译器错误:

1>MyControl.cpp
1>c:\program files (x86)\windows kits\10\include\10.0.17134.0\cppwinrt\winrt\base.h(6416): error C2079: 'winrt::impl::producer<D,winrt::Windows::UI::Xaml::Controls::Control,void>::vtable' uses undefined struct 'winrt::impl::produce<D,I>'
1>        with
1>        [
1>            D=MyApp::MyControl
1>        ]
1>c:\program files (x86)\windows kits\10\include\10.0.17134.0\cppwinrt\winrt\base.h(7163): note: see reference to class template instantiation 'winrt::impl::producer<D,winrt::Windows::UI::Xaml::Controls::Control,void>' being compiled
1>        with
1>        [
1>            D=MyApp::MyControl
1>        ]
1>c:\xxx\mycontrol.h(8): note: see reference to class template instantiation 'winrt::implements<MyApp::MyControl,winrt::Windows::UI::Xaml::Controls::Control>' being compiled

我无法理解编译器错误。显然,您无法像实现Windows运行时使用的其他类型一样实现XAML控件。

在代码中实现XAML自定义控件需要什么?

1 个答案:

答案 0 :(得分:3)

&#34;继承&#34;或&#34;继承&#34;在WinRT中与C ++继承略有不同。因为这些是COM接口,所以当你继承WinRT运行时类时,你真正做的是COM Aggregation,并结合实现基类型overridable interfaces。由于COM聚合方面,这比标准C ++继承更加繁琐,所有委托/非授权,特殊构造等都是如此。这将是WRL的一个主要难题,但C ++ / CX做了一堆编译魔术把它抽象出去的引擎盖。幸运的是,C ++ / WinRT可以帮助你提供两种类型的抽象,而不需要使用隐形魔法。

如果您正在创作一个不需要外部可见的类型(例如应用程序,而不是运行时组件),C ++ / WinRT为此提供了方便的帮助:

#pragma once

#include <winrt/Windows.UI.Xaml.Controls.h>

namespace MyApp
{
    struct MyControl : winrt::Windows::UI::Xaml::Controls::ControlT<MyControl>
    {
        void OnTapped(winrt::Windows::UI::Xaml::Input::TappedRoutedEventArgs const&);
    };
}

此基类型ControlT将正确构建聚合的基础Control实例并将基本方法委托给它,同时还实现&#34;可覆盖的&#34;接口。这些可覆盖的方法都有一个占位符实现,默认调用基本方法,但您可以自己覆盖它们并获得自定义行为。

另一方面,如果您需要通过IDL创作一个预计的类型:

namespace MyApp
{
  [default_interface]
  runtimeclass MyControl : Windows.UI.Xaml.Controls.Control
  {
    MyControl();
  };
}

这将生成与上面内置的ControlT案例类似的脚手架,但也会预测您的类型。实际上,如果您检查此类型的生成文件(在此示例中为MyControl.g.h),您会看到MyControlT所有内容都已连接起来。

(注意:只有当你有一个空的,可构造的,密封的运行时类时才需要[default_interface]属性。一旦你添加成员,midl将会合成默认接口,而不需要任何其他的哄骗。