Как сделать ObservableCollection потокобезопасным?

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

Я добавляю / удаляю из ObservableCollection, который не находится в потоке пользовательского интерфейса.

У меня есть имена методов EnqueueReport для добавления в colleciton и DequeueReport для удаления из colleciton.

поток шагов, как показано ниже : -

  1. 1.EnqueueReport звонят, когда новый доклад
  2. вызовите метод каждые несколько секунд, чтобы проверить, сгенерирован ли отчет (это имеет цикл foreach, который проверяет сгенерированный состояние всех отчетов в ObservableCollection)
  3. вызовите DequeueReport, если отчет генерируется

Я не очень много в библиотеках c#. Кто-нибудь может мне помочь?

4 ответов


вы можете создать простой поток дружественной версии наблюдаемой коллекции. Например:

 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);
                }
        }
    }

С этим теперь сделайте массивную находку и замените и измените все свои ObservableCollection to MTObservableCollection и ваш хорошо идти


решение, которое Франк разместил здесь, будет работать в случае, когда один поток добавляет вещи, но сам ObservableCollection (и список, на котором он основан) не являются потокобезопасными. Если в коллекцию записывается несколько потоков,могут быть введены труднодоступные ошибки. Я написал версию ObservableCollection, которая использует ReaderWriteLockSlim, чтобы быть действительно потокобезопасной.

к сожалению, он попал в предел символов StackOverflow, поэтому здесь он находится на PasteBin. Это должно работать 100% с несколькими читателями / писателями. Как и обычная ObservableCollection, недопустимо изменять коллекцию в обратном вызове из нее (в потоке, который получил обратный вызов).


начиная с .net framwork 4.5 вы можете использовать собственную синхронизацию коллекции.

BindingOperations.EnableCollectionSynchronization(YourCollection, YourLockObject);

YourLockObject является экземпляром любого объекта, например new Object();. Используйте по одному на коллекцию.

это исключает потребность некоторого особенного класса или что-нибудь. Просто включите и наслаждайтесь ;)

PS:BindingOperations находится в пространстве имен System.Windows.Data.


можно использовать класс ObservableConcurrentCollection. Они находятся в пакете, предоставленном Microsoft в библиотеке параллельных расширений Extras.

вы можете получить его предварительно построенным сообществом на Nuget: https://www.nuget.org/packages/ParallelExtensionsExtras/

или получить его от Microsoft здесь:

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