How to make ObservableCollection thread-safe?

谁说我不能喝 提交于 2019-12-17 06:36:06

问题


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

I am adding/removing from an ObservableCollection which is not on a UI thread.

I have a method names EnqueueReport to add to the colleciton and a DequeueReport to remove from the colleciton.

The flow of steps is as below :-

  1. 1.call EnqueueReport whenever a new report is requested
  2. call a method every few seconds to check if the report is generated (this has a foreach loop that checks the generated status of all reports in ObservableCollection)
  3. call DequeueReport if the report is generated

I am not much in C# libraries. Can someone please guide me on this?


回答1:


You can create a simple thread friendly version of the observable collection. Like the following :

 public class MTObservableCollection<T> : ObservableCollection<T>
    {
        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);
                }
        }
    }

with that now do a massive find & replace and change all your ObservableCollection to MTObservableCollection and your good to go




回答2:


As of .net framwork 4.5 you can use native collection synchronization.

BindingOperations.EnableCollectionSynchronization(YourCollection, YourLockObject);

YourLockObject is instance of any object e.g. new Object();. Use one per collection.

This eliminates the need of some special class or anything. Just enable and enjoy ;)

[edit] As stated in the comments by Mark and Ed (thanks for clarifying!), this does not relieve you from locking the collection on updates as it just synchonizes the collection-view-binding and does not magically make the collection thread-safe itself. [/edit]

PS: BindingOperations resides in Namespace System.Windows.Data.




回答3:


The solution Franck posted here will work in the case where one thread is adding things, but ObservableCollection itself (and List, which it's based on) are not thread-safe. If multiple threads are writing to the collection, hard-to-track-down bugs could be introduced. I wrote a version of ObservableCollection that uses a ReaderWriteLockSlim to be truly thread-safe.

Unfortunately, it hit the StackOverflow character limit, so here it is on PasteBin. This should work 100% with multiple readers/writers. Just like regular ObservableCollection, it's invalid to modify the collection in a callback from it (on the thread that received the callback).




回答4:


You can use a ObservableConcurrentCollection class. They are in a package provided by Microsoft in the Parallel Extensions Extras library.

You can get it prebuilt by the community on Nuget: https://www.nuget.org/packages/ParallelExtensionsExtras/

Or get it from Microsoft here:

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



来源:https://stackoverflow.com/questions/23108045/how-to-make-observablecollection-thread-safe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!