代码之家  ›  专栏  ›  技术社区  ›  IInspectable

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

  •  3
  • IInspectable  · 技术社区  · 6 年前

    我试图用C++实现一个自定义的XAML控件,使用C++/WRET。但是,我尝试的实现未能编译。作为概念证明,我使用了以下代码:

    #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 回复  |  直到 6 年前
        1
  •  3
  •   Ryan Shepherd    6 年前

    “继承”或“子类”在WinRT是微妙的不同于C++的继承。因为这些是COM接口,所以当您对WinRT RuntimeClass进行子类化时,您真正要做的是 COM Aggregation ,与实现基类型的 overridable interfaces .由于COM聚合方面,这比标准的C++继承更为繁琐,这与所有委托/非委托、特殊构造等有关。这将是WRL中的一个主要问题,但是C++/CX在引擎盖下做了一组编译器魔术来抽象这一点。幸运的是,C++/WiRT帮助你提供两种类型的抽象,而不诉诸不可见的魔法。

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

    #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 实例并将基方法委托给它,同时实现“可重写”接口。这些可重写的方法都被赋予了一个占位符实现,该实现默认为调用基方法,但您可以自己重写它们并获得自定义行为。

    另一方面,如果需要通过IDL编写已投影的类型:

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

    这将产生类似于内置的脚手架 控制 上面的案例,也可以投影您的类型。实际上,如果您检查此类型的生成文件(在本例中,mycontrol.g.h),您将看到 MyControlT 在那里,一切都被连接起来了。

    (注: [default_interface] 只有当您有一个空的、可构造的、密封的RuntimeClass时,才需要属性。一旦你添加了成员,MIDL将在不使用任何其他哄骗的情况下,计算出默认接口的合成。