为什么不能从不同的线程更新 ObservableCollection?

问题描述 投票:0回答:2

在多线程 WPF 应用程序中,不可能从 WPF 窗口线程以外的线程更新

ObservableCollection

我知道有解决方法,所以我的问题不是如何避免“这种类型的 CollectionView 不支持从与 Dispatcher 线程不同的线程更改其 SourceCollection ”异常。

我的问题是,为什么会出现这样的异常?为什么不允许从任何线程进行集合更新?

就我个人而言,当

ObservableCollection
从其他线程更改时,我不认为有任何理由阻止 UI 更新。如果两个线程(包括并行线程)正在访问同一个对象,一个线程通过事件侦听对象属性的更改,另一个线程执行更改,那么它将始终有效,至少在正确使用锁的情况下如此。那么,到底是什么原因呢?

c# wpf multithreading observablecollection
2个回答
18
投票

首先...我感受到你的痛苦。 Ui 线程限制可能会很痛苦......

为什么你不能更新 Ui 元素 一条不同于原来的线程 创建于?

我的问题是,为什么会有这样的 例外?

简而言之,历史。 Windows 已经存在了一段时间,Gui 的某些部分工作方式嵌入在 COM 等技术中......所以改变它并不是微不足道的......很容易破坏某些东西。我确信还有很多其他问题......但是比我聪明的人需要解释它们。我相信 WPF 团队确实想消除此限制,并且他们非常努力地工作...最后,我认为所需的核心操作系统更改数量是不可行的...所以他们继续前进...老鼠。

为什么不可能允许 来自任何线程的集合更新?

过去和现在都是可能的……使某些东西成为线程安全的总是会牺牲一些性能并增加复杂性。在大多数情况下,应用程序不需要多线程访问。重要的是要了解,在大多数情况下,Microsoft 遵循与我们相同的规则和相同的限制。如果他们让 ObservableCollection 成为线程安全的……他们就会使用我们拥有的相同工具……锁、监视器等。他们不能像我们一样破坏 Ui 线程规则……没有魔法……相同的规则。

我知道有解决方法,所以我的 问题不在于如何避免“这个 CollectionView 的类型不 支持对其进行更改 来自线程的 SourceCollection 与调度程序线程不同” 例外。

没有解决方法...没有什么可以解决的。 ObservableCollection 已损坏..它不是线程安全的。您必须使其或对它的访问成为线程安全的。这对于任何非线程安全的东西都是一样的......如果你需要它是线程安全的,那就让它如此。如果您使用线程,那么您就会了解锁等...使用它们..这就是它们的用途。

...阻止 UI 更新 ObservableCollection 更改自 其他线程....它总是有效的, 至少如果使用锁的话 正确地....

如果锁使用得当……没错!同样,微软本可以安装这些锁,但他们没有这么做,而且有充分的理由。您可以加锁。或者您可以使用其他策略来为您提供线程安全访问......很多选项。

.net4.0中的任务并行库提供了一些新的工具来解决这些问题。能够为任务或线程设置上下文特别有用......

  // get the Ui thread context
  _uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();

  Action DoInBackground = new Action(() =>
  {
    /*...In the background...
      ...process some data for an ObservableCollection...*/
  });

  Action DoOnUiThread = new Action(() =>
  { 
    /*...On the UI thread...
      ...read/write data to an ObservableCollection...*/
  });

  // start the background task
  var t1 = Task.Factory.StartNew(() => DoInBackground());
  // when t1 is done run t1..on the Ui thread.
  var t2 = t1.ContinueWith(t => DoOnUiThread(), _uiScheduler);

不要将 Ui Elements 的线程亲和性要求视为需要解决的问题......这只是它的工作方式。

C# 和 .Net 有许多可以使用的工具,可以让线程不再是一场噩梦。使用它们..它们会很有趣。

我要去抽烟了。


10
投票

如果您的集合绑定到用户界面元素,则这些用户界面元素将侦听集合的

CollectionChanged
事件,并在您更新集合的线程上引发此事件。

所以问题在于用户界面元素,它们只能从创建它们的线程访问,而不能从集合本身访问。

© www.soinside.com 2019 - 2024. All rights reserved.