参考关于 TreeView 的我的问题,建议我使用数据绑定来填充 TreView 的项目。
我在 Desktop C++ VS 2022 项目中创建了一个新的黑色应用程序,打包,WinUI3。
这将运行并显示按钮
我更改了 MainWindow IDL:
namespace App1
{
[default_interface]
runtimeclass MainWindow : Microsoft.UI.Xaml.Window, Microsoft.UI.Xaml.Data.INotifyPropertyChanged
{
MainWindow();
String MyProperty;
}
}
我改变了.h
namespace winrt::App1::implementation
{
struct MainWindow : MainWindowT<MainWindow>
{
winrt::hstring j = L"TEXT 1";
MainWindow()
{
// Xaml objects should not call InitializeComponent during construction.
// See https://github.com/microsoft/cppwinrt/tree/master/nuget#initializecomponent
}
winrt::hstring MyProperty();
void MyProperty(winrt::hstring);
void myButton_Click(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args);
winrt::event_token PropertyChanged(Microsoft::UI::Xaml::Data::PropertyChangedEventHandler const& value);
void PropertyChanged(winrt::event_token const& token);
winrt::event<Microsoft::UI::Xaml::Data::PropertyChangedEventHandler> m_propertyChanged;
};
}
namespace winrt::App1::factory_implementation
{
struct MainWindow : MainWindowT<MainWindow, implementation::MainWindow>
{
};
}
我更改.cpp:
#include "pch.h"
#include "MainWindow.xaml.h"
#if __has_include("MainWindow.g.cpp")
#include "MainWindow.g.cpp"
#endif
using namespace winrt;
using namespace Microsoft::UI::Xaml;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace winrt::App1::implementation
{
winrt::hstring MainWindow::MyProperty()
{
return j;
}
void MainWindow::MyProperty(winrt::hstring nv)
{
j = nv;
m_propertyChanged(*this, Microsoft::UI::Xaml::Data::PropertyChangedEventArgs{ L"Content" });
}
winrt::event_token MainWindow::PropertyChanged(Microsoft::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
{
return m_propertyChanged.add(handler);
}
void MainWindow::PropertyChanged(winrt::event_token const& token)
{
m_propertyChanged.remove(token);
}
void MainWindow::myButton_Click(IInspectable const&, RoutedEventArgs const&)
{
MyProperty(L"YO");
}
}
最后是 XAML:
<Button x:Name="myButton" Click="myButton_Click" Content="{x:Bind MyProperty, Mode=OneWay}"></Button>
这只有效一次。它曾经调用我的属性并将“TEXT 1”设置为按钮,但是当调用
myButton_Click
时,调用
m_propertyChanged(*this, Microsoft::UI::Xaml::Data::PropertyChangedEventArgs{ L"Content" });
什么也不做。该按钮不会更新其内容。
我做错了什么?
编辑:当我执行
m_propertyChanged(*this, Microsoft::UI::Xaml::Data::PropertyChangedEventArgs{ L"" });
时,即没有“Content”字符串,它就可以工作。
为什么?
它不能双向工作,因为您指定了
OneWay
模式:
<Button x:Name="myButton" Click="myButton_Click" Content="{x:Bind MyProperty, Mode=OneWay}"></Button>
所以只需这样声明:
<Button x:Name="myButton" Click="myButton_Click" Content="{x:Bind MyProperty, Mode=TwoWay}"></Button>
但是当您使用 C++/WinRT 执行此操作时,您可能会收到此类错误(请注意,在 .NET 和 C# 中,它会正常工作):
MainWindow.xaml.g.hpp(155,71): error C2665: 'winrt::to_hstring': no overloaded function could convert all the argument types
这是因为
Content
是 IDL 中的 Object
类型(又名 IInspectable
),而你的属性在 IDL 中是 String
类型(又名 hstring
),并且没有隐式转换,另请参阅 https:/ /github.com/microsoft/cppwinrt/issues/942
因此,您可以修复它,例如在 MainWindow.xaml.h 中创建此转换(模仿 C++/WinRT 的
base.h
to_hstring
重载):
WINRT_EXPORT namespace winrt
{
inline hstring to_hstring(IInspectable value)
{
auto pv = value.try_as<IPropertyValue>();
if (pv && pv.Type() == PropertyType::String)
return pv.GetString();
return L"???";
}
}
还要确保您的财产免受无限循环的影响:
void MainWindow::MyProperty(hstring value)
{
if (_myProperty == value)
return;
_myProperty = value;
RaisePropertyChanged(L"MyProperty");
}
我在这里创建了一个示例应用程序:https://github.com/smourier/WinUI3Cpp