在C++/WinRT、WinUI 3中实现返回winrt::event_revoker的自定义类型事件注册器
正确实现WinRT自定义类型的INotifyPropertyChanged自动撤销器
问题根源
你之前的错误是因为winrt::event_revoker依赖公共WinRT接口的方法指针,而非implementation类的私有方法;同时构造revoker时需要传入公共接口的弱引用,而非implementation类的弱引用。
标准实现步骤
1. 调整头文件定义
在winrt::Test::implementation::MyType的头文件中,修正revoker类型声明与重载方法:
namespace winrt::Test::implementation { struct MyType : MyTypeT<MyType> { // 保留原有基础事件实现 winrt::event_token PropertyChanged(winrt::Microsoft::UI::Xaml::Data::PropertyChangedEventHandler const& handler); void PropertyChanged(winrt::event_token const& token); // 定义基于公共接口的撤销器类型 using PropertyChanged_revoker = winrt::event_revoker<Test::MyType>; // 声明带auto_revoke的重载方法 PropertyChanged_revoker PropertyChanged(winrt::auto_revoke_t, winrt::Microsoft::UI::Xaml::Data::PropertyChangedEventHandler const& handler); private: winrt::event<winrt::Microsoft::UI::Xaml::Data::PropertyChangedEventHandler> propertyChanged_; }; }
2. 实现带自动撤销的重载方法
在cpp文件中,正确构造event_revoker:
winrt::event_token winrt::Test::implementation::MyType::PropertyChanged(winrt::Microsoft::UI::Xaml::Data::PropertyChangedEventHandler const& handler) { return propertyChanged_.add(handler); } void winrt::Test::implementation::MyType::PropertyChanged(winrt::event_token const& token) { propertyChanged_.remove(token); } winrt::Test::implementation::MyType::PropertyChanged_revoker winrt::Test::implementation::MyType::PropertyChanged(winrt::auto_revoke_t, winrt::Microsoft::UI::Xaml::Data::PropertyChangedEventHandler const& handler) { // 获取公共接口的弱引用(而非implementation类的弱引用) auto weak_public_this = winrt::make_weak<Test::MyType>(*this); // 直接使用公共接口的PropertyChanged(event_token)方法作为撤销逻辑 return PropertyChanged_revoker(weak_public_this, &Test::MyType::PropertyChanged, propertyChanged_.add(handler)); }
3. 使用撤销器并存入vector
调用方代码示例:
// 存储撤销器的容器 std::vector<winrt::Test::implementation::MyType::PropertyChanged_revoker> event_revokers; // 创建MyType实例 auto my_type = winrt::make<winrt::Test::implementation::MyType>(); // 添加带自动撤销的事件处理器,将revoker存入vector event_revokers.emplace_back( my_type.PropertyChanged(winrt::auto_revoke, [](auto&& sender, auto&& args) { // 处理属性变更逻辑 winrt::hstring prop_name = args.PropertyName(); // ... }) );
关键说明
- 无需自定义
unregisterPropertyChanged方法:公共接口Test::MyType已继承INotifyPropertyChanged的PropertyChanged(event_token)方法,直接复用即可。 - 必须使用公共接口的弱引用:
winrt::make_weak<Test::MyType>(*this)将implementation实例转换为公共接口的弱引用,符合event_revoker的ABI调用要求。 - 避免修改WinRT库内部实现:你的临时方案修改了
event_revoker的源码,会破坏库的兼容性与规范性,标准实现完全无需此类操作。
内容的提问来源于stack exchange,提问作者ridilculous
相关产品推荐
相关产品推荐

