我很满意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
被绑定在XAML
中。
那么基本上应该发生什么 - >如果在另一个线程上调用Run()
函数,它应该抛出一个跨线程异常,不应该吗?我在代码中有两个地方,在一个地方它总是抛出一个异常,在第二个地方永远不会抛出异常。我已经比较了线程ID,并且在两个地方Run()
都没有在UI线程上运行。为什么会这样?
在它没有抛出异常的地方,我将它绑定到UserControl中的Dependency属性,然后我使用普通绑定将其绑定
抛出异常:{"The calling thread cannot access this object because a different thread owns it."}
看起来我没有找到适合这种特殊情况的答案。 UiModel及其绑定不会引发异常,但UiModel也用于ReactiveUI验证。如果我不从UI更新它,它将尝试从导致该异常的其他线程更新CanExecuteChanged。不过我的问题仍然是一样的 - 为什么我可以从不同的线程更新UI而没有交叉线程异常?我无法在ReactiveUI PropertyChanged调用中看到调度程序调用。
答案 0 :(得分:3)
这个领域有一些烦人的不一致。以下是您可以从工作线程执行和不能执行的操作列表。
引发跨线程异常:
False
DependencyProperty
事件ICommand.CanExecuteChanged
INotifyCollectionChanged.CollectionChanged
事件
不会抛出异常:
ObservableCollection<T>
事件我确信WPF没有自动调用第一个列表是有充分理由的,但我想不出它可能是什么。
我处理服务事件的建议是:
INotifyPropertyChanged.PropertyChanged
捕获的引用(这可能是您最常用的)。