using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; namespace BetterLyrics.WinUI3.Collections { // https://stackoverflow.com/a/32013610/11048731 public class FullyObservableCollection : ObservableCollection where T : INotifyPropertyChanged { /// /// Occurs when a property is changed within an item. /// public event EventHandler ItemPropertyChanged; public FullyObservableCollection() : base() { } public FullyObservableCollection(List list) : base(list) { ObserveAll(); } public FullyObservableCollection(IEnumerable enumerable) : base(enumerable) { ObserveAll(); } protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if (e.Action == NotifyCollectionChangedAction.Remove || e.Action == NotifyCollectionChangedAction.Replace) { foreach (T item in e.OldItems) item.PropertyChanged -= ChildPropertyChanged; } if (e.Action == NotifyCollectionChangedAction.Add || e.Action == 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 (T item in Items) item.PropertyChanged += ChildPropertyChanged; } private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e) { T typedSender = (T)sender; int i = Items.IndexOf(typedSender); if (i < 0) throw new ArgumentException("Received property notification from item not in collection"); OnItemPropertyChanged(i, e); } public void Refresh() { OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } } /// /// 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) { } } }