演示项目包含一个简单的 GUI,带有按钮和派生的用户控件 MyUserControl。 MyUserControl 仅包含一个边框,其背景绑定到用户控件的背景:
void MyUserControl::CreateGui()
{
winrt::Microsoft::UI::Xaml::Controls::Border b;
Content(b);
b.BorderThickness(winrt::Microsoft::UI::Xaml::Thickness{ 1, 1, 1, 1 });
b.BorderBrush(winrt::Microsoft::UI::Xaml::Media::SolidColorBrush(winrt::Windows::UI::Colors::Black()));
winrt::Microsoft::UI::Xaml::Data::Binding binding;
binding.Source(*this);
binding.Path(winrt::Microsoft::UI::Xaml::PropertyPath(L"Background"));
b.SetBinding(winrt::Microsoft::UI::Xaml::Controls::Border::BackgroundProperty(), binding);
}
MyUserControl 还注册了自己的 DependencyProperty AnotherBrush,其类型为 Brush:
void MyUserControl::InitClass()
{
mAnotherBrushProperty =
Microsoft::UI::Xaml::DependencyProperty::Register(
L"AnotherBrush",
winrt::xaml_typename<winrt::Microsoft::UI::Xaml::Media::Brush>(),
winrt::xaml_typename<winrt::UnpackagedDesktopApp::MyUserControl>(),
Microsoft::UI::Xaml::PropertyMetadata(nullptr)
);
}
InitClass 在创建 MainWindow 之前在 App::OnLaunched 中调用。 当MainWindow初始化时,MyUserControl实例的画笔被设置:
mUC = winrt::UnpackagedDesktopApp::MyUserControl();
sp.Children().Append(mUC);
mUC.Width(200);
mUC.Height(100);
mUC.Background(winrt::Microsoft::UI::Xaml::Media::SolidColorBrush(winrt::Windows::UI::Colors::GreenYellow()));
mUC.AnotherBrush(winrt::Microsoft::UI::Xaml::Media::SolidColorBrush(winrt::Windows::UI::Colors::Red()));
mUC.Foreground(winrt::Microsoft::UI::Xaml::Media::SolidColorBrush(winrt::Windows::UI::Colors::CornflowerBlue()));
按下按钮时,MyUserControl 实例的背景会绑定到其自己的依赖属性 AnotherBrush:
void MainWindow::myButton_Click(IInspectable const&, RoutedEventArgs const&)
{
auto checkAnotherBrush = mUC.AnotherBrush();
winrt::Microsoft::UI::Xaml::Data::Binding binding;
binding.Source(mUC);
binding.Path(winrt::Microsoft::UI::Xaml::PropertyPath(L"AnotherBrush")); //doesn't work!!
//binding.Path(winrt::Microsoft::UI::Xaml::PropertyPath(L"Foreground")); //works
mUC.SetBinding(winrt::Microsoft::UI::Xaml::Controls::Control::BackgroundProperty(), binding);
auto checkUCBackground = mUC.Background();
mBtn.Content(box_value(L"Clicked"));
}
MyUserControl 的背景现在应具有与 AnotherBrush 相同的颜色(即红色)。调试时,可以从变量 checkAnotherBrush 中看到 AnotherBrush 确实被设置了。但是,变量 checkUCBackground 显示应用绑定后背景意外地为 NULL。 但是,如果背景绑定到内置的 Foreground 属性,则它可以工作!
演示应用程序可以在这里下载: 演示应用程序.zip
由于这是一个基本功能,我怀疑这不是框架中的错误,而是我做错了什么。但什么?
测试条件如下:
更新:
按照YangXiaoPo的建议,我还实现了INotifyPropertyChanged并扩展了MyUserControl,如下所示:
//MyUserControl.idl
runtimeclass MyUserControl : Microsoft.UI.Xaml.Controls.UserControl, Microsoft.UI.Xaml.Data.INotifyPropertyChanged
{
...
void NotifyPropertyChanged(String propertyName);
}
//MyUserControl.h
struct MyUserControl : MyUserControlT<MyUserControl>
{
...
static void OnAnotherBrushChanged(Microsoft::UI::Xaml::DependencyObject d, Microsoft::UI::Xaml::DependencyPropertyChangedEventArgs e);
winrt::event_token PropertyChanged(winrt::Microsoft::UI::Xaml::Data::PropertyChangedEventHandler const& handler);
void PropertyChanged(winrt::event_token const& token) noexcept;
winrt::event<Microsoft::UI::Xaml::Data::PropertyChangedEventHandler> mPropertyChanged;
void NotifyPropertyChanged(hstring const& propertyName);
};
//MyUserControl.cpp
void MyUserControl::InitClass()
{
mAnotherBrushProperty =
Microsoft::UI::Xaml::DependencyProperty::Register(
L"AnotherBrush",
winrt::xaml_typename<winrt::Microsoft::UI::Xaml::Media::Brush>(),
winrt::xaml_typename<winrt::UnpackagedDesktopApp::MyUserControl>(),
Microsoft::UI::Xaml::PropertyMetadata{ nullptr, Microsoft::UI::Xaml::PropertyChangedCallback{ &MyUserControl::OnAnotherBrushChanged } }
);
}
...
void MyUserControl::OnAnotherBrushChanged(Microsoft::UI::Xaml::DependencyObject d, Microsoft::UI::Xaml::DependencyPropertyChangedEventArgs e)
{
d.as<winrt::UnpackagedDesktopApp::MyUserControl>().NotifyPropertyChanged(L"AnotherBrush");
}
winrt::event_token MyUserControl::PropertyChanged(winrt::Microsoft::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
{
return mPropertyChanged.add(handler);
}
void MyUserControl::PropertyChanged(winrt::event_token const& token) noexcept
{
mPropertyChanged.remove(token);
}
void MyUserControl::NotifyPropertyChanged(hstring const& propertyName)
{
mPropertyChanged(*this, Microsoft::UI::Xaml::Data::PropertyChangedEventArgs{ propertyName });
}
NotifyPropertyChanged 方法被正确调用,但这不会改变任何内容。应用绑定后,Background 的值仍设置为 NULL。
请参阅 [https://github.com/microsoft/microsoft-ui-xaml/issues/9678][1]
Evelyn Wu(Miscrosoft)回答:
因为您的自定义控件既未在 XAML 标记中使用,也未在其 用 [bindable] 属性修饰的 IDL 声明,XamlCompiler 不知道它,因此不会生成任何类型 其信息。因此,从框架的角度来看 运行时不存在具有 AnotherBrush 属性的类型 MyUserControl。
您可以通过两种方式之一解决此问题(并确保添加 #include “MyUserControl.h”到 App.xaml.h 以避免构建中断):
在 MyUserControl.idl 中使用 [bindable] 属性修饰 MyUserControl 的声明
将 MyUserControl 的实例添加到项目的 .xaml 文件之一。