WPF和NotifyPropertyChanged来自不同的线程

时间:2016-07-19 08:02:34

标签: c# wpf multithreading

我很满意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调用中看到调度程序调用。

1 个答案:

答案 0 :(得分:3)

这个领域有一些烦人的不一致。以下是您可以从工作线程执行和不能执行的操作列表。

引发跨线程异常:

  • 修改控件上的False
  • 提升DependencyProperty事件
  • 通常从ICommand.CanExecuteChanged
  • 的实例提升INotifyCollectionChanged.CollectionChanged事件

不会抛出异常:

  • 通常从视图模型绑定中提升ObservableCollection<T>事件

我确信WPF没有自动调用第一个列表是有充分理由的,但我想不出它可能是什么。

我处理服务事件的建议是:

  1. 从UI线程维护对INotifyPropertyChanged.PropertyChanged捕获的引用(这可能是您最常用的)。
  2. 使用中介服务在UI线程上调用应用程序事件处理程序