我对 WPF 非常熟悉,但有一件事困扰着我。我正在使用 ReactiveUI 引发 INotifyPropertyChanged 事件。我有两个地方与此类似:
public UiModel UiModel
{
get { return _uiModel; }
set { this.RaiseAndSetIfChanged(ref _uiModel, value); }
}
public void Run()
{
UiModel = GetUIModel();
}
其中 Run()
是这样调用的 await Task.Run(()=>Run());
并且 UiModel
是绑定(bind)的在 XAML
中。
那么基本上应该发生什么 -> 如果在不同的线程上调用 Run()
函数,它应该抛出一个跨线程异常,不是吗?我在代码中有两个地方,在一个地方它总是抛出异常,在第二个地方永远不会抛出异常。我已经比较了线程 ID,并且在这两个地方 Run()
都没有在 UI 线程上运行。为什么会这样?
在它不抛出异常的地方,我将它绑定(bind)到 UserControl 中的依赖属性,然后我使用普通绑定(bind)将它绑定(bind)
抛出异常:{“调用线程无法访问此对象,因为另一个线程拥有它。”}
看来我已经找到了针对这种特定情况的答案。异常不是由 UiModel 抛出的,它是绑定(bind)的,但 UiModel 也用于 ReactiveUI 验证。如果我不从 UI 更新它,它将尝试从导致该异常的不同线程更新 CanExecuteChanged。尽管如此,我的问题仍然是一样的——为什么我可以从不同的线程更新 UI 而没有跨线程异常?我在 ReactiveUI PropertyChanged 调用中看不到调度程序调用。
最佳答案
这方面存在一些恼人的不一致。以下是您可以和不能从工作线程执行的操作列表。
引发跨线程异常:
- 修改
DependencyProperty
在控件上 - 提高
ICommand.CanExecuteChanged
事件 - 提高
INotifyCollectionChanged.CollectionChanged
事件,通常来自ObservableCollection<T>
的实例
不抛出异常:
- 提高
INotifyPropertyChanged.PropertyChanged
事件,通常来自 View 模型绑定(bind)
我确信 WPF 不自动调用第一个列表是有充分理由的,但我想不出它可能是什么。
我对处理服务事件的建议是:
- 维护对
SynchronizationContext
的引用从 UI 线程捕获(可能在这里对您最有用)。 - 使用中介服务在 UI 线程上调用应用程序事件处理程序
关于c# - 来自不同线程的 WPF 和 NotifyPropertyChanged,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38452688/