【问题标题】:How to modify an ObservableCollection from a different thread in .Net Standard 2.0?如何从 .Net Standard 2.0 中的不同线程修改 ObservableCollection?
【发布时间】:2018-07-27 19:51:42
【问题描述】:

我在 .Net Standard 2.0 中有一个库,用于多个项目(Xamarin、WPF、...),它使用 ObservableCollection 将它们绑定到 WPF 中或能够对它们的修改做出反应。

当我尝试从新线程的这些集合中删除一个元素时。然后它抛出一个“NotSupportedException”,通常使用Dispatcher解决,从UI线程调用remove方法。

问题在于 .Net Standard 不提供 Dispatcher(这是有道理的,因为可能没有 UI 线程)。所以这引出了我的问题;如何在没有 Dispatcher 的情况下从另一个线程修改这些集合?在这里使用 ObservableCollections 是不是在做一些我不应该做的事情?

例外:

System.NotSupportedException: This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.
à System.Windows.Data.CollectionView.OnCollectionChanged(Object sender,     NotifyCollectionChangedEventArgs args)
à System.Collections.ObjectModel.ObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs e)
à ALX.GroundStation.Host.Infrastructure.ReadOnlyObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs e)

【问题讨论】:

  • 这与 .NET Standard 无关,它不会打扰 UI。这是由您的运行时特定代码引发的,因为您尝试从另一个线程修改 UI,不,您不需要 Dispatcher 或 Invoke 来解决此问题。自 2012 年以来,远更容易使用 async/await
  • 而且您肯定不需要调度程序调用 UI 线程从的东西。反过来会导致问题。你的代码是什么样的?你在使用数据绑定吗?为什么您希望 library 将控件绑定到 ViewModel 属性而不是指定绑定表达式?
  • 为什么还要从其他线程修改 ObservableCollection?这不会加快添加对象的速度,它会使 UI 看起来更生硬,因为每次添加都会强制重绘。
  • 最后,发布 Exception.ToString() 返回的 full 异常,而不仅仅是类型名称。没有代码会引发 NotSupportedException in the source code
  • @PanagiotisKanavos 这正是我在工作中必须使用的。该集合获取新项目,并从多个网络线程中删除项目。我正在更新我的问题,但有例外,但这是常规问题

标签: c# wpf collections .net-standard .net-standard-2.0


【解决方案1】:

您可以简单地将适当的调度程序传递给库:

public void ThreadSafeAddItem(Item item, Dispatcher dispatcher)
{
    dispatcher.Invoke(()=> { AddItem(item); } );
}

但由于 .Net 标准 2.0 没有 Dispatcher 类,因此您需要委托在 WPF 项目中执行此操作。

public event Action<Item> ItemAdded;
public void ThreadSafeAddItem(Item item)
{
    if(ItemAdded!=null) ItemAdded(item);
}

在你的 WPF 中:

 Library.ItemAdded += (item) => {
     Dispatcher.Invoke(()=>Library.ObservCollection.Add(item));
 };

在另一个线程中:

 Library.ThreadSafeAddItem(item);

在这里使用 ObservableCollections 是不是在做我不应该做的事情

根据 MSDN:

要完全支持将数据值从绑定源对象传输到绑定目标,集合中支持可绑定属性的每个对象都必须实现适当的属性更改通知机制,例如 INotifyPropertyChanged 接口。

这可能意味着每个可绑定属性也需要这种机制,从而在您的应用中产生巨大的开销。

建议对库使用线程安全的方法(如 POCO 模型),而不是在另一个层(如 ViewModel)中处理这些绑定

【讨论】:

  • Dispatcher 在 .NET Standard 2.0 中不存在。此外,最好不要尝试修改来自不同线程或库的线程不安全集合。 返回数据到 UI 线程并让它添加它们。 Dispatcher.Invoke 做同样的事情,开销更大,阻塞风险很高
  • 这如何回答“我如何从另一个线程without a Dispatcher修改这些集合?”的问题
  • @MickyD 是的,很抱歉,我不知道我取消了该答案。无论如何,我更新了我的答案,请看一下。
  • 您的委托解决方案听起来可行,如果有人有更好的解决方案,我仍然会稍等,否则我会接受您的:)
猜你喜欢
  • 2018-06-21
  • 1970-01-01
  • 1970-01-01
  • 2018-07-15
  • 2018-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多