如何使ObservableCollection线程安全?

System.InvalidOperationException: Collection was modified; enumeration operation may not execute. 

我正在添加/删除不在UI线程上的ObservableCollection。

我有一个方法名称EnqueueReport添加到colleciton和DequeueReport从集合中删除。

步骤流程如下: –

  1. 1.call EnqueueReport每当请求新报告时
  2. 每隔几秒调用一次方法来检查是否生成了报告(这有一个foreach循环,用于检查ObservableCollection中所有报告的生成状态)
  3. 如果生成报告,则调用DequeueReport

我在C#库中并不多。 有人可以指导我吗?

您可以创建一个简单的线程友好版本的observable集合。 如下:

  public class MTObservableCollection : ObservableCollection { public override event NotifyCollectionChangedEventHandler CollectionChanged; protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { NotifyCollectionChangedEventHandler CollectionChanged = this.CollectionChanged; if (CollectionChanged != null) foreach (NotifyCollectionChangedEventHandler nh in CollectionChanged.GetInvocationList()) { DispatcherObject dispObj = nh.Target as DispatcherObject; if (dispObj != null) { Dispatcher dispatcher = dispObj.Dispatcher; if (dispatcher != null && !dispatcher.CheckAccess()) { dispatcher.BeginInvoke( (Action)(() => nh.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))), DispatcherPriority.DataBind); continue; } } nh.Invoke(this, e); } } } 

现在做一个大规模的查找和替换,并将所有的ObservableCollection更改为MTObservableCollection ,你的好处去

Franck在这里发布的解决方案将适用于一个线程正在添加内容的情况,但ObservableCollection本身(以及它所基于的List)不是线程安全的。 如果多个线程正在写入集合,则可能会引入难以跟踪的错误。 我编写了一个ObservableCollection版本,它使用ReaderWriteLockSlim来实现真正的线程安全。

不幸的是,它达到了StackOverflow字符限制,因此它在PasteBin上。 这应该与多个读者/作者100%一起工作。 就像常规的ObservableCollection一样,在回调中修改集合(在收到回调的线程上)是无效的。

从.net framwork 4.5开始,您可以使用本机集合同步。

BindingOperations.EnableCollectionSynchronization(YourCollection, YourLockObject);

YourLockObject是任何对象的实例,例如new Object(); 。 每个系列使用一个。

这消除了一些特殊类或任何东西的需要。 只需启用并享受;)

PS: BindingOperations驻留在命名空间System.Windows.Data

您可以使用ObservableConcurrentCollection类。 它们位于Microsoft在Parallel Extensions Extras库中提供的包中。

你可以在Nuget社区预先建立它: https ://www.nuget.org/packages/ParallelExtensionsExtras/

或者从Microsoft获取它:

https://code.msdn.microsoft.com/ParExtSamples