System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
J'ajoute/supprime une ObservableCollection qui n'est pas sur un thread d'interface utilisateur.
J'ai une méthode nommée EnqueueReport à ajouter à la colleciton et une DequeueReport à retirer de la colleciton.
Le déroulement des étapes est le suivant: -
Je ne suis pas beaucoup dans les bibliothèques C #. Quelqu'un peut-il me guider à ce sujet?
Vous pouvez créer une version simple et conviviale des threads de la collection observable. Comme le suivant:
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);
}
}
}
avec cela, faites maintenant une recherche et un remplacement massifs et changez tous vos ObservableCollection
en MTObservableCollection
et votre bon aller
Depuis .net framwork 4.5, vous pouvez utiliser la synchronisation de collection native.
BindingOperations.EnableCollectionSynchronization(YourCollection, YourLockObject);
YourLockObject
est une instance de n'importe quel objet, par exemple new Object();
. Utilisez-en un par collection.
Cela élimine le besoin d'une classe spéciale ou quoi que ce soit. Il suffit d'activer et de profiter;)
[modifier] Comme indiqué dans les commentaires de Mark et Ed (merci pour la clarification!), cela ne pas vous soulage de verrouiller la collection sur les mises à jour car il synchronise simplement la collection-view-binding et ne rend pas comme par magie la collection thread-safe elle-même. [/ modifier]
PS: BindingOperations
réside dans l'espace de noms System.Windows.Data
.
La solution que Franck a postée ici fonctionnera dans le cas où un thread ajoute des choses, mais ObservableCollection lui-même (et List, sur lequel il est basé) ne sont pas thread-safe. Si plusieurs threads écrivent dans la collection, des bogues difficiles à localiser peuvent être introduits. J'ai écrit une version d'ObservableCollection qui utilise un ReaderWriteLockSlim pour être vraiment thread-safe.
Malheureusement, il a atteint la limite de caractères StackOverflow, donc ici c'est sur Pastebin. Cela devrait fonctionner à 100% avec plusieurs lecteurs/écrivains. Tout comme ObservableCollection ordinaire, il n'est pas valide de modifier la collection dans un rappel à partir d'elle (sur le thread qui a reçu le rappel).
Vous pouvez utiliser une classe ObservableConcurrentCollection. Ils se trouvent dans un package fourni par Microsoft dans la bibliothèque Parallel Extensions Extras.
Vous pouvez le faire préconstruire par la communauté sur Nuget: https://www.nuget.org/packages/ParallelExtensionsExtras/
Ou obtenez-le auprès de Microsoft ici: