【问题标题】:Why isn't it possible to update an ObservableCollection from a different thread?为什么不能从不同的线程更新 ObservableCollection?
【发布时间】:2010-06-05 14:04:09
【问题描述】:

在多线程 WPF 应用程序中,从 WPF 窗口线程以外的线程更新 ObservableCollectionnot possible

我知道there are workarounds,所以我的问题不是如何避免“这种类型的 CollectionView 不支持从不同于 Dispatcher 线程的线程更改其 SourceCollection”异常。 p>

我的问题是,为什么会有这样的异常?为什么不能允许任何线程的集合更新?

就我个人而言,当ObservableCollection 从其他线程更改时,我认为没有任何理由阻止 UI 更新。如果两个线程(包括并行线程)正在访问同一个对象,一个通过事件监听对象属性的变化,另一个做变化,它总是可以工作的,至少如果锁使用得当的话。那么,究竟是什么原因呢?

【问题讨论】:

标签: c# wpf multithreading observablecollection


【解决方案1】:

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

为什么不能从 一个不同于它原来的线程 创建于 ?

我的问题是,为什么会有这样一个 异常?

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

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

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

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

没有解决方法...没有解决方法。 ObservableCollection 坏了..它只是不是线程安全的。您必须使其或访问它成为线程安全的。这对于任何不是线程安全的东西都是一样的……如果你需要它是线程安全的,那么就让它成为线程安全的。如果您使用线程,那么您就知道锁之类的......使用它们......这就是它们的用途。

...阻止 UI 更新 ObservableCollection 从 其他线程....它将始终有效, 至少在使用锁的情况下 妥妥的……

如果锁使用得当……没错!同样,微软本可以把这些锁放进去,但他们没有这样做,而且有很好的理由。你可以把锁放进去。或者你使用其他的策略来给你线程安全的访问....很多选项。

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

  // 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 元素的线程关联性要求视为可以解决的问题......这就是它的工作方式。

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

我要去抽烟。

【讨论】:

    【解决方案2】:

    如果您的集合绑定到用户界面元素,则这些用户界面元素正在侦听集合的 CollectionChanged 事件,并在您更新集合的线程上引发此事件。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-06-17
      • 2019-11-14
      • 1970-01-01
      • 2014-03-20
      • 2010-10-18
      • 1970-01-01
      相关资源
      最近更新 更多