Hicimos una rápida implementación a mí mismo:
public class ObservableCollectionEx<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
Unsubscribe(e.OldItems);
Subscribe(e.NewItems);
base.OnCollectionChanged(e);
}
protected override void ClearItems()
{
foreach(T element in this)
element.PropertyChanged -= ContainedElementChanged;
base.ClearItems();
}
private void Subscribe(IList iList)
{
if (iList != null)
{
foreach (T element in iList)
element.PropertyChanged += ContainedElementChanged;
}
}
private void Unsubscribe(IList iList)
{
if (iList != null)
{
foreach (T element in iList)
element.PropertyChanged -= ContainedElementChanged;
}
}
private void ContainedElementChanged(object sender, PropertyChangedEventArgs e)
{
OnPropertyChanged(e);
}
}
admitió que sería un poco confuso y engañoso tener el fuego PropertyChanged en la colección cuando la propiedad que cambió realmente está en un elemento de contenido, pero sería se ajusta a mi propósito específico. Podría extenderse con un nuevo evento que se active dentro de ContainerElementChanged
¿Pensamientos?
EDIT: Debe tener en cuenta que el BCL ObservableCollection sólo expone la interfaz INotifyPropertyChanged través de una implementación explícita lo que sería necesario para proporcionar un molde con el fin de insertarse en el caso de este modo:
ObservableCollectionEx<Element> collection = new ObservableCollectionEx<Element>();
((INotifyPropertyChanged)collection).PropertyChanged += (x,y) => ReactToChange();
Edit2: manejo Añadido de ClearItems, gracias Josh
Edit3: añadido un darse de baja correcta para PropertyChanged, gracias Marcos
EDIT4: Wow, esto es realmente aprender-as-you-go :). KP notó que el evento se disparó con la colección como remitente y no con el elemento cuando el elemento a contenido cambia. Sugirió declarar un evento PropertyChanged en la clase marcada con new. Esto tendría un par de temas que voy a tratar de ilustrar con el ejemplo siguiente:
// work on original instance
ObservableCollection<TestObject> col = new ObservableCollectionEx<TestObject>();
((INotifyPropertyChanged)col).PropertyChanged += (s, e) => { Trace.WriteLine("Changed " + e.PropertyName); };
var test = new TestObject();
col.Add(test); // no event raised
test.Info = "NewValue"; //Info property changed raised
// working on explicit instance
ObservableCollectionEx<TestObject> col = new ObservableCollectionEx<TestObject>();
col.PropertyChanged += (s, e) => { Trace.WriteLine("Changed " + e.PropertyName); };
var test = new TestObject();
col.Add(test); // Count and Item [] property changed raised
test.Info = "NewValue"; //no event raised
se puede ver en la muestra que 'de primer orden' el evento tiene el efecto secundario que tiene que ser extremadamente cuidadoso de los cuales tipo de variable que utiliza al suscribirse al evento, ya que eso determina qué eventos recibe.
Marcando esto como la respuesta como nada mejor (en mi opinión) ha surgido –
Sin embargo, hay un problema con esta clase. Si llama a Clear(), el evento OnCollectionChanged recibirá una notificación de reinicio y no tendrá acceso a los elementos que se eliminaron de la colección. Esto puede mitigarse anulando ClearItems y anulando la suscripción a los manejadores antes de llamar a base.ClearItems(). – Josh
Bien atrapado, Josh. He actualizado el código para reflejar esto. –