Rozwiązanie
ReadOnlyObservableCollection.CollectionChanged nie jest ujawniona (z ważnych powodów opisanych w innych odpowiedziach), więc stwórzmy własną klasę opakowującą, która ją ujawnia:
public class ObservableReadOnlyCollection<T> : ReadOnlyObservableCollection<T>
{
public new NotifyCollectionChangedEventHandler CollectionChanged;
public ObservableReadOnlyCollection(ObservableCollection<T> list) : base(list) { }
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs args) =>
CollectionChanged?.Invoke(this, args);
}
Wyjaśnienie
Ludzie pytają, dlaczego chciałbyś obserwować zmiany w zbiorze tylko do odczytu, więc wyjaśnię jedną z wielu ważnych sytuacji; gdy kolekcja tylko do odczytu otacza prywatną kolekcję wewnętrzną, która może ulec zmianie.
Oto jeden taki scenariusz:
Załóżmy, że masz usługę, która umożliwia dodawanie i usuwanie elementów do wewnętrznej kolekcji spoza usługi. Teraz załóżmy, że chcesz ujawnić wartości kolekcji, ale nie chcesz, aby konsumenci bezpośrednio manipulowali kolekcją; więc opakowujesz wewnętrzną kolekcję w plik ReadOnlyObservableCollection.
Zauważ, że aby opakować kolekcję wewnętrzną z ReadOnlyObservableCollectionkolekcją wewnętrzną, jest ona zmuszona ObservableCollectionprzez konstruktoraReadOnlyObservableCollection .
Teraz przypuśćmy, że chcesz powiadomić konsumentów o usłudze, gdy zmieni się kolekcja wewnętrzna (a tym samym kiedy ujawnione ReadOnlyObservableCollectionzmiany). Zamiast toczenia własną implementację chcesz tylko wystawiać CollectionChangedz ReadOnlyObservableCollection. Zamiast zmuszać konsumenta do przyjęcia założenia na temat implementacji ReadOnlyObservableCollection, wystarczy zamienić rozszerzenieReadOnlyObservableCollection ten zwyczaj ObservableReadOnlyCollectioni gotowe.
Do ObservableReadOnlyCollectionskóry ReadOnlyObservableCollection.CollectionChangedz jego rękę, a po prostu przechodzi na wszystkich zbiórki zmienionych zdarzeń do wszelkich załączonych obsługi zdarzeń.