How to make ObservableCollection thread-safe?

前端 未结 4 848
天命终不由人
天命终不由人 2020-11-29 03:42
System.InvalidOperationException: Collection was modified; enumeration operation may not execute.

I am adding/removing from an ObservableCollection

相关标签:
4条回答
  • 2020-11-29 04:02

    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

    0 讨论(0)
  • 2020-11-29 04:04

    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

    0 讨论(0)
  • 2020-11-29 04:15

    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.

    0 讨论(0)
  • 2020-11-29 04:20

    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).

    0 讨论(0)
提交回复
热议问题