/// <summary> /// Binds a <see cref="NotifyCollectionChangedEventHandler"/> to all collections by the name <paramref name="collectionPropertyName"/> on the elements of type <typeparamref name="T"/> on the specified collection. /// Note: not all elements of <paramref name="collection"/> are considered; only those of type <typeparamref name="T"/>. You could specify <see cref="INotifyPropertyChanged"/> to revert this. /// </summary> /// <returns> a disposble which unhooks the <paramref name="handler"/> from all elements. </returns> public static IDisposable BindElements <TCollection, T>( this TCollection collection, string collectionPropertyName, NotifyCollectionChangedEventHandler handler) where T : INotifyPropertyChanged where TCollection : INotifyCollectionChanged, IEnumerable <object> { Contract.Requires(collection != null); Contract.Requires(handler != null); PropertyChangedEventHandler intermediate = (element, e) => { if (e.PropertyName == collectionPropertyName) { var _e = (IPropertyMutatedEventArgs)e; if (_e.OldValue is INotifyCollectionChanged oldCollection) { oldCollection.CollectionChanged -= handler; } if (_e.NewValue is INotifyCollectionChanged newCollection) { newCollection.CollectionChanged += handler; } } }; var collectionHandler = CollectionChangedEventHandler <object> .Create <TCollection>(add : add, remove : remove); collection.CollectionChanged += collectionHandler.CollectionChanged; return(new Disposable(() => { collection.CollectionChanged -= collectionHandler.CollectionChanged; foreach (T element in collection) { element.PropertyChanged -= intermediate; } })); void add(TCollection sender, IReadOnlyList <object> newElements, int index) { Contract.Assert(ReferenceEquals(collection, sender)); foreach (T element in newElements.OfType <T>()) { element.PropertyChanged += intermediate; intermediate(element, PropertyMutatedEventArgsExtensions.From(element, collectionPropertyName)); } } void remove(TCollection sender, IReadOnlyList <object> oldElements, int index) { Contract.Assert(ReferenceEquals(collection, sender)); foreach (T element in oldElements.OfType <T>()) { element.PropertyChanged -= intermediate; } } }
/// <summary> /// Binds a <see cref="PropertyChangedEventHandler"/> to all elements on the specified collection. /// </summary> /// <returns> a disposble which unhooks the <paramref name="handler"/> from all elements. </returns> public static IDisposable BindElements <TCollection, T>(this TCollection collection, PropertyChangedEventHandler handler) where T : INotifyPropertyChanged where TCollection : INotifyCollectionChanged, IEnumerable <T> { Contract.Requires(collection != null); Contract.Requires(handler != null); var collectionHandler = CollectionChangedEventHandler <T> .Create <TCollection>(add : add, remove : remove); collection.CollectionChanged += collectionHandler.CollectionChanged; return(new Disposable(() => { collection.CollectionChanged -= collectionHandler.CollectionChanged; foreach (T element in collection) { element.PropertyChanged -= handler; } })); void add(TCollection sender, IReadOnlyList <T> newElements, int index) { Contract.Assert(ReferenceEquals(collection, sender)); foreach (T element in newElements) { element.PropertyChanged += handler; } } void remove(TCollection sender, IReadOnlyList <T> oldElements, int index) { Contract.Assert(ReferenceEquals(collection, sender)); foreach (T element in oldElements) { element.PropertyChanged -= handler; } } }