未打包的桌面应用程序:绑定到自己的依赖项属性不起作用

问题描述 投票:0回答:1

演示项目包含一个简单的 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

由于这是一个基本功能,我怀疑这不是框架中的错误,而是我做错了什么。但什么?

测试条件如下:

  • WinUI 3 - Windows 应用程序 SDK 1.5.3:1.5.240428000
  • Windows 10 (21H2):内部版本 19044
  • Microsoft Visual Studio Community 2022(64 位)- 当前版本 17.10.0

更新:

按照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。

windows desktop-application c++-winrt windows-app-sdk
1个回答
0
投票

请参阅 [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 以避免构建中断):

  1. 在 MyUserControl.idl 中使用 [bindable] 属性修饰 MyUserControl 的声明

  2. 将 MyUserControl 的实例添加到项目的 .xaml 文件之一。

© www.soinside.com 2019 - 2024. All rights reserved.