使用PropertyChanged更新TextBlock时触发跨线程崩溃(错误0x8001010E)
问题原因
错误0x8001010E的核心原因是:你在非UI线程触发了PropertyChanged事件,而XAML UI元素只能在创建它们的UI线程中更新,跨线程直接操作会导致线程编组不匹配,引发崩溃。
解决方案
必须确保PropertyChanged事件始终在UI线程触发,以下是两种高效的实现方式:
方式1:直接在属性设置方法中处理线程调度
修改WordArray.cpp中的AllWord方法,加入线程检查与UI线程调度逻辑:
#include <Microsoft.UI.Dispatching.h> void WordArray::AllWord(winrt::hstring const& value) { if (m_allword != value) { m_allword = value; // 获取当前线程的DispatcherQueue auto dispatcherQueue = Microsoft::UI::Dispatching::DispatcherQueue::GetForCurrentThread(); if (dispatcherQueue.HasThreadAccess()) { // 当前处于UI线程,直接触发事件 m_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"AllWord" }); } else { // 非UI线程,调度到UI线程执行事件触发 dispatcherQueue.TryEnqueue([this]() { m_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"AllWord" }); }); } } }
方式2:封装基类复用线程调度逻辑
创建一个BindableBase基类,所有需要实现INotifyPropertyChanged的ViewModel都继承它,统一处理线程调度逻辑,避免重复代码:
1. 实现BindableBase基类
// BindableBase.h namespace winrt::Lexical_Frequency::implementation { struct BindableBase : winrt::implements<BindableBase, Windows::UI::Xaml::Data::INotifyPropertyChanged> { winrt::event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler) { return m_propertyChanged.add(handler); } void PropertyChanged(winrt::event_token const& token) { m_propertyChanged.remove(token); } protected: void OnPropertyChanged(winrt::hstring const& propertyName) { auto dispatcherQueue = Microsoft::UI::Dispatching::DispatcherQueue::GetForCurrentThread(); if (dispatcherQueue.HasThreadAccess()) { m_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ propertyName }); } else { dispatcherQueue.TryEnqueue([this, propertyName]() { m_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ propertyName }); }); } } private: winrt::event<Windows::UI::Xaml::Data::PropertyChangedEventHandler> m_propertyChanged; }; }
2. 修改WordArray继承BindableBase
// WordArray.h namespace winrt::Lexical_Frequency::implementation { struct WordArray : WordArrayT<WordArray, BindableBase> { // 保留原有构造函数和AllWord读取方法 void AllWord(winrt::hstring const& value) { if (m_allword != value) { m_allword = value; // 调用基类方法自动处理线程调度 OnPropertyChanged(L"AllWord"); } } }; }
3. 移除WordArray中重复的PropertyChanged代码
由于基类已经实现了INotifyPropertyChanged接口的全部方法,删除WordArray.cpp中以下代码:
winrt::event_token WordArray::PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler) { return m_propertyChanged.add(handler); } void WordArray::PropertyChanged(winrt::event_token const& token) { m_propertyChanged.remove(token); }
额外注意事项
如果你的AllWord方法是从后台线程调用的(比如异步文件操作的回调),也可以在调用时直接调度到UI线程:
void DataPage::SaveFileButton_Click(IInspectable const&, RoutedEventArgs const&) { // 假设GetFileNameSave是异步操作,完成后在后台线程回调 GetFileNameSave().Completed([this](auto const&, auto) { // 调度到UI线程更新属性 DispatcherQueue().TryEnqueue([this]() { MainViewModel().WordArray().AllWord(L"To Kill a Mockingbird"); }); }); }
内容的提问来源于stack exchange,提问作者Extremeer
相关产品推荐
相关产品推荐

