Como fazer o ObservableCollection thread-safe?

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

Eu estou adicionando / removendo de um ObservableCollection que não está em um thread de interface do usuário.

Eu tenho um nome de método EnqueueReport para adicionar ao colleciton e um DequeueReport para remover do colleciton.

O stream de etapas é como abaixo:

  1. 1.call EnqueueReport sempre que um novo relatório for solicitado
  2. chame um método a cada poucos segundos para verificar se o relatório é gerado (isso tem um loop foreach que verifica o status gerado de todos os relatórios em ObservableCollection)
  3. chamar DequeueReport se o relatório for gerado

Eu não sou muito em bibliotecas C #. Alguém pode me guiar por isso?

Você pode criar uma versão simples de thread da coleção observável. Como o seguinte:

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

com isso, agora faça um grande achado e substitua e mude todo o seu ObservableCollection para MTObservableCollection e você pode ir

A solução que Franck postou aqui irá funcionar no caso em que um thread está adicionando coisas, mas o próprio ObservableCollection (e List, no qual ele é baseado) não é thread-safe. Se vários segmentos estiverem gravando na coleção, poderão ser introduzidos erros difíceis de rastrear. Eu escrevi uma versão do ObservableCollection que usa um ReaderWriteLockSlim para ser verdadeiramente thread-safe.

Infelizmente, ele atingiu o limite de caracteres StackOverflow, então aqui está no PasteBin. Isso deve funcionar 100% com vários leitores / gravadores. Assim como o ObservableCollection regular, é inválido modificar a coleção em um retorno de chamada dele (no encadeamento que recebeu o retorno de chamada).

A partir do .net framwork 4.5, você pode usar a synchronization de coleção nativa.

BindingOperations.EnableCollectionSynchronization(YourCollection, YourLockObject);

YourLockObject é a instância de qualquer object, por exemplo, new Object(); . Use um por coleção.

Isso elimina a necessidade de alguma class especial ou qualquer coisa. Basta ativar e desfrutar;)

PS: BindingOperations reside no Namespace System.Windows.Data .

Você pode usar uma class ObservableConcurrentCollection. Eles estão em um pacote fornecido pela Microsoft na biblioteca Parallel Extensions Extras.

Você pode obtê-lo pré-construído pela comunidade em Nuget: https://www.nuget.org/packages/ParallelExtensionsExtras/

Ou obtenha da Microsoft aqui:

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