using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; namespace FModel.Framework; public class FullyObservableCollection : ObservableCollection where T : INotifyPropertyChanged { /// /// Occurs when a property is changed within an item. /// public event EventHandler ItemPropertyChanged; public FullyObservableCollection() { } public FullyObservableCollection(List list) : base(list) { ObserveAll(); } public FullyObservableCollection(IEnumerable enumerable) : base(enumerable) { ObserveAll(); } protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if (e.Action is NotifyCollectionChangedAction.Remove or NotifyCollectionChangedAction.Replace) { foreach (T item in e.OldItems) item.PropertyChanged -= ChildPropertyChanged; } if (e.Action is NotifyCollectionChangedAction.Add or NotifyCollectionChangedAction.Replace) { foreach (T item in e.NewItems) item.PropertyChanged += ChildPropertyChanged; } base.OnCollectionChanged(e); } protected void OnItemPropertyChanged(ItemPropertyChangedEventArgs e) { ItemPropertyChanged?.Invoke(this, e); } protected void OnItemPropertyChanged(int index, PropertyChangedEventArgs e) { OnItemPropertyChanged(new ItemPropertyChangedEventArgs(index, e)); } protected override void ClearItems() { foreach (T item in Items) item.PropertyChanged -= ChildPropertyChanged; base.ClearItems(); } private void ObserveAll() { foreach (var item in Items) item.PropertyChanged += ChildPropertyChanged; } private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e) { var typedSender = (T) sender; var i = Items.IndexOf(typedSender); if (i < 0) throw new ArgumentException("Received property notification from item not in collection"); OnItemPropertyChanged(i, e); } } /// /// Provides data for the event. /// public class ItemPropertyChangedEventArgs : PropertyChangedEventArgs { /// /// Gets the index in the collection for which the property change has occurred. /// /// /// Index in parent collection. /// public int CollectionIndex { get; } /// /// Initializes a new instance of the class. /// /// The index in the collection of changed item. /// The name of the property that changed. public ItemPropertyChangedEventArgs(int index, string name) : base(name) { CollectionIndex = index; } /// /// Initializes a new instance of the class. /// /// The index. /// The instance containing the event data. public ItemPropertyChangedEventArgs(int index, PropertyChangedEventArgs args) : this(index, args.PropertyName) { } }