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 ReadOnlyObservableCollection
kolekcją wewnętrzną, jest ona zmuszona ObservableCollection
przez konstruktoraReadOnlyObservableCollection
.
Teraz przypuśćmy, że chcesz powiadomić konsumentów o usłudze, gdy zmieni się kolekcja wewnętrzna (a tym samym kiedy ujawnione ReadOnlyObservableCollection
zmiany). Zamiast toczenia własną implementację chcesz tylko wystawiać CollectionChanged
z ReadOnlyObservableCollection
. Zamiast zmuszać konsumenta do przyjęcia założenia na temat implementacji ReadOnlyObservableCollection
, wystarczy zamienić rozszerzenieReadOnlyObservableCollection
ten zwyczaj ObservableReadOnlyCollection
i gotowe.
Do ObservableReadOnlyCollection
skóry ReadOnlyObservableCollection.CollectionChanged
z jego rękę, a po prostu przechodzi na wszystkich zbiórki zmienionych zdarzeń do wszelkich załączonych obsługi zdarzeń.