¿Cómo hacer que ObservableCollection sea seguro para subprocesos?

¿Cómo hacer que ObservableCollection sea seguro para subprocesos?

A partir de .NET Framework 4.5, puede usar la sincronización de colecciones nativa.

BindingOperations.EnableCollectionSynchronization(YourCollection, YourLockObject);

YourLockObject es una instancia de cualquier objeto, p. new Object(); . Usa uno por colección.

Esto elimina la necesidad de alguna clase especial o cualquier cosa. Solo habilita y disfruta;)

[editar] Como se indica en los comentarios de Mark y Ed (¡gracias por aclarar!), esto no lo libera de bloquear la colección en las actualizaciones, ya que solo sincroniza el enlace de la vista de la colección y no mágicamente hace que la colección sea segura para subprocesos.[/edit]

PD:BindingOperations reside en el espacio de nombres System.Windows.Data .


La solución que Franck publicó aquí funcionará en el caso de que un subproceso esté agregando cosas, pero ObservableCollection en sí mismo (y List, en el que se basa) no son seguros para subprocesos. Si varios subprocesos están escribiendo en la colección, se podrían introducir errores difíciles de rastrear. Escribí una versión de ObservableCollection que usa un ReaderWriteLockSlim para ser verdaderamente seguro para subprocesos.

Desafortunadamente, alcanzó el límite de caracteres de StackOverflow, así que aquí está en PasteBin. Esto debería funcionar al 100% con múltiples lectores/escritores. Al igual que ObservableCollection regular, no es válido modificar la colección en una devolución de llamada (en el hilo que recibió la devolución de llamada).


Puede crear una versión simple compatible con subprocesos de la colección observable. Me gusta lo siguiente:

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

con eso ahora haz una búsqueda y reemplazo masivos y cambia todos tus ObservableCollection a MTObservableCollection y estás listo para ir