WinUI3 WinRT/C++原生桌面应用无法创建Xaml UserControl
WinUI3 C++/WinRT 自定义UserControl编译错误排查
问题背景
创建极简WinUI3 WinRT/C++桌面(空白、打包)项目并添加UserControl后,原本可正常编译运行。为实现DependencyProperty功能修改代码时出现以下问题:
- 尝试给实现类添加UserControl继承时,触发静态断言错误:
static_assert failed: 'Class must derive from implements<> or ClassT<> where the first template parameter is the derived class name, e.g. struct D : implements<D, ...>'
- 尝试添加DependencyProperty时,提示OneWay模式需实现INotifyPropertyChange,但添加该接口继承时又提示已是基类。
现有代码文件
CalcButton.idl
namespace ThirdCppAppv3 { [default_interface] runtimeclass CalcButton : Microsoft.UI.Xaml.Controls.UserControl { CalcButton(); } }
CalcButton.xaml
<?xml version="1.0" encoding="utf-8"?> <UserControl x:Class="ThirdCppAppv3.CalcButton" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:ThirdCppAppv3" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center"> <Button x:Name="myButton" Click="myButton_Click" Content="Custom Button"></Button> </StackPanel> </UserControl>
CalcButton.xaml.h
#pragma once #include "CalcButton.g.h" namespace winrt::ThirdCppAppv3::implementation { struct CalcButton : CalcButtonT<CalcButton, Microsoft::UI::Xaml::Controls::UserControl> { CalcButton(); void myButton_Click(IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&); }; } namespace winrt::ThirdCppAppv3::factory_implementation { struct CalcButton : CalcButtonT<CalcButton, implementation::CalcButton> { }; }
CalcButton.xaml.cpp
#include "pch.h" #include "CalcButton.xaml.h" #include "CalcButton.g.cpp" using namespace winrt; using namespace Microsoft::UI::Xaml; namespace winrt::ThirdCppAppv3::implementation { CalcButton::CalcButton() { } void CalcButton::myButton_Click(IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&) { } }
解决方案
1. 修复继承结构错误
C++/WinRT中,工具生成的CalcButtonT基类已自动关联idl中声明的UserControl基类,实现类无需显式继承Microsoft::UI::Xaml::Controls::UserControl。修改CalcButton.xaml.h中的实现类定义:
namespace winrt::ThirdCppAppv3::implementation { // 移除第二个模板参数,仅保留派生类名称 struct CalcButton : CalcButtonT<CalcButton> { CalcButton(); void myButton_Click(IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&); }; }
2. 初始化XAML内容
构造函数中必须调用InitializeComponent(),否则XAML控件不会加载,这是易忽略的关键步骤:
CalcButton::CalcButton() { InitializeComponent(); // 添加此行代码 }
3. DependencyProperty相关问题说明
- 自定义DependencyProperty无需手动实现
INotifyPropertyChanged,DependencyProperty本身已支持属性变更通知,OneWay绑定模式对其天然兼容,之前的错误提示是继承结构混乱导致的编译干扰。 - 若要添加自定义DependencyProperty,可参考以下示例(以添加
ButtonText属性为例):
在idl中添加属性声明:
在[default_interface] runtimeclass CalcButton : Microsoft.UI.Xaml.Controls.UserControl { CalcButton(); static Microsoft.UI.Xaml.DependencyProperty ButtonTextProperty{ get; }; string ButtonText{ get; set; }; }CalcButton.xaml.cpp中实现属性逻辑:
最后在XAML中绑定该属性:namespace winrt::ThirdCppAppv3::implementation { Microsoft::UI::Xaml::DependencyProperty CalcButton::ButtonTextProperty() { static auto property = Microsoft::UI::Xaml::DependencyProperty::Register( L"ButtonText", winrt::xaml_typename<winrt::hstring>(), winrt::xaml_typename<ThirdCppAppv3::CalcButton>(), Microsoft::UI::Xaml::PropertyMetadata{ winrt::box_value(L"Custom Button") } ); return property; } winrt::hstring CalcButton::ButtonText() { return winrt::unbox_value<winrt::hstring>(GetValue(ButtonTextProperty())); } void CalcButton::ButtonText(winrt::hstring const& value) { SetValue(ButtonTextProperty(), winrt::box_value(value)); } }<Button x:Name="myButton" Click="myButton_Click" Content="{x:Bind ButtonText, Mode=OneWay}"></Button>
内容的提问来源于stack exchange,提问作者Peter Vermilye
相关产品推荐
相关产品推荐

