J'ai moi-même procédé à une mise en œuvre rapide :
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);
}
}
Il est vrai qu'il serait un peu déroutant et trompeur d'avoir le PropertyChanged déclenché sur la collection alors que la propriété qui a réellement changé se trouve sur un élément contenu, mais cela répondrait à mon objectif spécifique. Il pourrait être étendu avec un nouvel événement qui est déclenché à la place de ContainerElementChanged
Réflexions ?
EDIT : Il convient de noter que la BCL ObservableCollection n'expose l'interface INotifyPropertyChanged que par le biais d'une implémentation explicite, de sorte que vous devriez fournir un cast afin de vous attacher à l'événement de cette manière :
ObservableCollectionEx<Element> collection = new ObservableCollectionEx<Element>();
((INotifyPropertyChanged)collection).PropertyChanged += (x,y) => ReactToChange();
EDIT2 : Ajout de la gestion de ClearItems, merci Josh
EDIT3 : Ajout d'un désabonnement correct pour PropertyChanged, merci Mark
EDIT4 : Wow, c'est vraiment de l'apprentissage au fur et à mesure :). KP a noté que l'événement était déclenché avec la collection comme expéditeur et non avec l'élément lorsque l'élément a contenu change. Il a suggéré de déclarer un événement PropertyChanged sur la classe marquée par le symbole nouveau . Cela poserait quelques problèmes que j'essaierai d'illustrer avec l'exemple ci-dessous :
// 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
Vous pouvez voir dans l'exemple que le fait de "surcharger" l'événement a pour effet secondaire de vous obliger à faire extrêmement attention au type de variable que vous utilisez lorsque vous vous abonnez à l'événement, car cela dicte les événements que vous recevez.