Mengapa ReadOnlyObservableCollection.CollectionChanged
dilindungi dan tidak bersifat publik (sebagaimana yang sesuai ObservableCollection.CollectionChanged
)?
Apa gunanya implementasi collection INotifyCollectionChanged
jika saya tidak dapat mengakses CollectionChanged
acara?
c#
.net
collections
Oskar
sumber
sumber
Jawaban:
Berikut solusinya: Peristiwa CollectionChanged di ReadOnlyObservableCollection
Anda harus mentransmisikan koleksi ke INotifyCollectionChanged .
sumber
Saya telah menemukan cara bagi Anda untuk melakukan ini:
ObservableCollection<string> obsCollection = new ObservableCollection<string>(); INotifyCollectionChanged collection = new ReadOnlyObservableCollection<string>(obsCollection); collection.CollectionChanged += new NotifyCollectionChangedEventHandler(collection_CollectionChanged);
Anda hanya perlu merujuk ke koleksi Anda secara eksplisit dengan antarmuka INotifyCollectionChanged .
sumber
ReadOnlyObservableCollection
Anda akan menemukan ini:event NotifyCollectionChangedEventHandler INotifyCollectionChanged.CollectionChanged
. Implementasi antarmuka eksplisit dari acara tersebut.Saya tahu posting ini sudah tua, namun, orang harus meluangkan waktu untuk memahami pola yang digunakan dalam .NET sebelum berkomentar. Koleksi hanya-baca adalah pembungkus pada koleksi yang ada yang mencegah konsumen untuk memodifikasinya secara langsung, lihat
ReadOnlyCollection
dan Anda akan melihat bahwa itu adalah pembungkusIList<T>
yang mungkin atau mungkin tidak bisa berubah. Koleksi yang tidak dapat diubah adalah masalah yang berbeda dan dilindungi oleh perpustakaan koleksi yang tidak dapat diubah yang baruDengan kata lain, read only tidak sama dengan immutable !!!!
Selain itu,
ReadOnlyObservableCollection
harus diterapkan secara implisitINotifyCollectionChanged
.sumber
Pasti ada alasan bagus untuk ingin berlangganan notifikasi koleksi yang diubah di ReadOnlyObservableCollection . Jadi, sebagai alternatif untuk hanya mentransmisikan koleksi Anda sebagai INotifyCollectionChanged , jika Anda kebetulan menjadi subclass ReadOnlyObservableCollection , berikut ini menyediakan cara yang lebih nyaman secara sintaksis untuk mengakses acara CollectionChanged :
public class ReadOnlyObservableCollectionWithCollectionChangeNotifications<T> : ReadOnlyObservableCollection<T> { public ReadOnlyObservableCollectionWithCollectionChangeNotifications(ObservableCollection<T> list) : base(list) { } event System.Collections.Specialized.NotifyCollectionChangedEventHandler CollectionChanged2 { add { CollectionChanged += value; } remove { CollectionChanged -= value; } } }
Ini telah bekerja dengan baik untuk saya sebelumnya.
sumber
Anda dapat memilih entri bug di Microsoft Connect yang menjelaskan masalah ini: https://connect.microsoft.com/VisualStudio/feedback/details/641395/readonlyobservablecollection-t-collectionchanged-event-should-be-public
Memperbarui:
Portal Connect telah ditutup oleh Microsoft. Jadi link di atas tidak berfungsi lagi.
Perpustakaan My Win Application Framework (WAF) menyediakan solusi: kelas ReadOnlyObservableList :
public class ReadOnlyObservableList<T> : ReadOnlyObservableCollection<T>, IReadOnlyObservableList<T> { public ReadOnlyObservableList(ObservableCollection<T> list) : base(list) { } public new event NotifyCollectionChangedEventHandler CollectionChanged { add { base.CollectionChanged += value; } remove { base.CollectionChanged -= value; } } public new event PropertyChangedEventHandler PropertyChanged { add { base.PropertyChanged += value; } remove { base.PropertyChanged -= value; } } }
sumber
Seperti yang sudah dijawab, Anda memiliki dua opsi: Anda dapat mentransmisikan
ReadOnlyObservableCollection<T>
ke antarmukaINotifyCollectionChanged
untuk mengaksesCollectionChanged
peristiwa yang diimplementasikan secara eksplisit , atau Anda dapat membuat kelas pembungkus Anda sendiri yang melakukannya sekali di konstruktor dan hanya menghubungkan peristiwa yang dibungkusReadOnlyObservableCollection<T>
.Beberapa wawasan tambahan tentang mengapa masalah ini belum diperbaiki:
Seperti yang Anda lihat dari kode sumber ,
ReadOnlyObservableCollection<T>
adalah publik, kelas non-tertutup (yaitu mewarisi), di mana peristiwa ditandaiprotected virtual
.Artinya, mungkin ada program yang dikompilasi dengan kelas yang diturunkan dari
ReadOnlyObservableCollection<T>
, dengan definisi acara yang diganti tetapiprotected
visibilitas. Program tersebut akan berisi kode yang tidak valid setelah visibilitas acara diubah menjadipublic
di kelas dasar, karena tidak diizinkan untuk membatasi visibilitas acara di kelas turunan.Sungguh sayang, bikin
protected virtual
acarapublic
kemudian hari adalah perubahan yang menghancurkan biner, dan karenanya tidak akan dilakukan tanpa alasan yang sangat baik, yang saya khawatirkan "Saya harus melemparkan objek sekali untuk memasang penangan" tidak.Sumber: Komentar GitHub oleh Nick Guererra, 19 Agustus 2015
sumber
Ini adalah hit teratas di google jadi saya pikir saya akan menambahkan solusi saya jika orang lain mencari ini.
Menggunakan informasi di atas (tentang perlunya mentransmisikan ke INotifyCollectionChanged ), saya membuat dua metode ekstensi untuk mendaftar dan membatalkan pendaftaran.
Solusi Saya - Metode Ekstensi
public static void RegisterCollectionChanged(this INotifyCollectionChanged collection, NotifyCollectionChangedEventHandler handler) { collection.CollectionChanged += handler; } public static void UnregisterCollectionChanged(this INotifyCollectionChanged collection, NotifyCollectionChangedEventHandler handler) { collection.CollectionChanged -= handler; }
Contoh
IThing.cs
public interface IThing { string Name { get; } ReadOnlyObservableCollection<int> Values { get; } }
Menggunakan Metode Ekstensi
public void AddThing(IThing thing) { //... thing.Values.RegisterCollectionChanged(this.HandleThingCollectionChanged); } public void RemoveThing(IThing thing) { //... thing.Values.UnregisterCollectionChanged(this.HandleThingCollectionChanged); }
Solusi OP
public void AddThing(IThing thing) { //... INotifyCollectionChanged thingCollection = thing.Values; thingCollection.CollectionChanged += this.HandleThingCollectionChanged; } public void RemoveThing(IThing thing) { //... INotifyCollectionChanged thingCollection = thing.Values; thingCollection.CollectionChanged -= this.HandleThingCollectionChanged; }
Alternatif 2
public void AddThing(IThing thing) { //... (thing.Values as INotifyCollectionChanged).CollectionChanged += this.HandleThingCollectionChanged; } public void RemoveThing(IThing thing) { //... (thing.Values as INotifyCollectionChanged).CollectionChanged -= this.HandleThingCollectionChanged; }
sumber
Larutan
ReadOnlyObservableCollection.CollectionChanged
tidak terekspos (untuk alasan valid yang diuraikan dalam jawaban lain), jadi mari buat kelas pembungkus kita sendiri yang memaparkannya:/// <summary>A wrapped <see cref="ReadOnlyObservableCollection{T}"/> that exposes the internal <see cref="CollectionChanged"/>"/>.</summary> public class ObservableReadOnlyCollection<T> : ReadOnlyObservableCollection<T> { public new NotifyCollectionChangedEventHandler CollectionChanged; public ObservableReadOnlyCollection(ObservableCollection<T> list) : base(list) { /* nada */ } protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs args) => CollectionChanged?.Invoke(this, args); }
Penjelasan
Orang-orang bertanya mengapa Anda ingin mengamati perubahan pada koleksi hanya-baca, jadi saya akan menjelaskan salah satu dari banyak situasi yang valid; saat koleksi hanya-baca membungkus koleksi internal pribadi yang bisa berubah.
Inilah salah satu skenario tersebut:
Misalkan Anda memiliki layanan yang memungkinkan penambahan dan penghapusan item ke koleksi internal dari luar layanan. Sekarang misalnya Anda ingin mengekspos nilai-nilai koleksi tetapi Anda tidak ingin konsumen memanipulasi koleksi secara langsung; jadi Anda membungkus koleksi internal dalam file
ReadOnlyObservableCollection
.Sekarang misalkan Anda ingin memberi tahu konsumen tentang layanan saat koleksi internal berubah (dan karenanya saat terekspos
ReadOnlyObservableCollection
berubah). Daripada menjalankan implementasi Anda sendiri, Anda hanya ingin mengeksposCollectionChanged
fileReadOnlyObservableCollection
. Daripada memaksa konsumen untuk membuat asumsi tentang implementasiReadOnlyObservableCollection
, Anda cukup menukarReadOnlyObservableCollection
dengan kebiasaan iniObservableReadOnlyCollection
, dan selesai.The
ObservableReadOnlyCollection
menyembunyikanReadOnlyObservableCollection.CollectionChanged
dengan itu sendiri, dan hanya melewati semua peristiwa berubah koleksi untuk setiap event terlampir.sumber