tag propiedad c# .net-3.5 collections

propiedad tag c#



¿Qué colección.Net para agregar múltiples objetos a la vez y recibir notificaciones? (11)

Estaba considerando la clase System.Collections.ObjectModel ObservableCollection<T> . Este es extraño porque

  • tiene un método Add que solo toma un elemento. Sin AddRange o equivalente.
  • los argumentos del evento de notificación tienen una propiedad NewItems, que es un IList (de objetos ... no T)

Mi necesidad aquí es agregar un lote de objetos a una colección y el oyente también obtiene el lote como parte de la notificación. ¿Me estoy perdiendo algo con ObservableCollection? ¿Hay otra clase que cumpla con mi especificación?

Actualización: No quiero hacer mi propio todo lo posible. Tendría que construir en agregar / eliminar / cambiar, etc. un montón de cosas.

Q relacionado:
https://stackoverflow.com/questions/670577/observablecollection-doesnt-support-addrange-method-so-i-get-notified-for-each


¿Heredar de List <T> y anular los métodos Add () y AddRange () para generar un evento?


Bueno, la idea es la misma que la de fryguybob, algo extraño que ObservableCollection está medio hecho. El evento args para esto ni siquiera usa Generics ... haciéndome usar un IList (eso es ... ayer :) Probado El fragmento sigue ...

using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; namespace MyNamespace { public class ObservableCollectionWithBatchUpdates<T> : ObservableCollection<T> { public void AddRange(ICollection<T> obNewItems) { IList<T> obAddedItems = new List<T>(); foreach (T obItem in obNewItems) { Items.Add(obItem); obAddedItems.Add(obItem); } NotifyCollectionChangedEventArgs obEvtArgs = new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Add, obAddedItems as System.Collections.IList); base.OnCollectionChanged(obEvtArgs); } } }



Extension Method Man al rescate!

/// <summary> /// Adds all given items to the collection /// </summary> /// <param name="collection">The collection.</param> /// <param name="toAdd">Objects to add.</param> public static void AddAll<T>(this IList<T> collection, params T[] toAdd) { foreach (var o in toAdd) collection.Add(o); }


He visto este tipo de preguntas muchas veces, y me pregunto por qué incluso Microsoft está promocionando ObservableCollection en todas partes donde hay una mejor colección ya disponible, eso es ...

BindingList<T>

Lo que le permite desactivar las notificaciones y realizar operaciones masivas y luego activar las notificaciones.


No solo es una buena apuesta a System.Collections.ObjectModel.Collection<T> , sino que en los documentos de ayuda hay un ejemplo de cómo sobrescribir sus diversos métodos protegidos para recibir notificaciones. (Desplácese hacia abajo al Ejemplo 2)


Otra solución que es similar al patrón CollectionView:

public class DeferableObservableCollection<T> : ObservableCollection<T> { private int deferLevel; private class DeferHelper<T> : IDisposable { private DeferableObservableCollection<T> owningCollection; public DeferHelper(DeferableObservableCollection<T> owningCollection) { this.owningCollection = owningCollection; } public void Dispose() { owningCollection.EndDefer(); } } private void EndDefer() { if (--deferLevel <= 0) { deferLevel = 0; OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } } public IDisposable DeferNotifications() { deferLevel++; return new DeferHelper<T>(this); } protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if (deferLevel == 0) // Not in a defer just send events as normally { base.OnCollectionChanged(e); } // Else notify on EndDefer } }


Para agregar rápidamente, puede usar:

((List<Person>)this.Items).AddRange(NewItems);


Parece que la interfaz INotifyCollectionChanged permite la actualización cuando se agregaron varios elementos, por lo que no estoy seguro de por qué ObservableCollection<T> no tiene un AddRange . Podría hacer un método de extensión para AddRange , pero eso causaría un evento por cada elemento que se agrega. Si eso no es aceptable, debería poder heredar de ObservableCollection<T> siguiente manera:

public class MyObservableCollection<T> : ObservableCollection<T> { // matching constructors ... bool isInAddRange = false; protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { // intercept this when it gets called inside the AddRange method. if (!isInAddRange) base.OnCollectionChanged(e); } public void AddRange(IEnumerable<T> items) { isInAddRange = true; foreach (T item in items) Add(item); isInAddRange = false; var e = new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Add, items.ToList()); base.OnCollectionChanged(e); } }


Si quiere heredar de algún tipo una colección, probablemente sea mejor heredar de System.Collections.ObjectModel.Collection porque proporciona métodos virtuales para anular. Tendrás que sombrear los métodos fuera de List si vas por esa ruta.

No conozco ninguna colección incorporada que brinde esta funcionalidad, aunque me gustaría que me corrijan :)


Si utiliza cualquiera de las implementaciones anteriores que envían un comando agregar rango y enlaza la colección observable a una vista de lista, obtendrá este desagradable error.

NotSupportedException at System.Windows.Data.ListCollectionView.ValidateCollectionChangedEventArgs(NotifyCollectionChangedEventArgs e) at System.Windows.Data.ListCollectionView.ProcessCollectionChanged(NotifyCollectionChangedEventArgs args) at System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Object sender, NotifyCollectionChangedEventArgs e) at System.Collections.ObjectModel.ObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs e)

La implementación con la que he trabajado utiliza el evento Reset que se implementa de manera más uniforme en todo el marco WPF:

public void AddRange(IEnumerable<T> collection) { foreach (var i in collection) Items.Add(i); OnPropertyChanged("Count"); OnPropertyChanged("Item[]"); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); }