Microsoft seharusnya menerapkan sesuatu yang cepat INotifyPropertyChanged
, seperti pada properti otomatis, sebutkan saja {get; set; notify;}
saya pikir itu masuk akal untuk melakukannya. Atau adakah komplikasi untuk melakukannya?
Bisakah kita menerapkan sesuatu seperti 'beri tahu' di properti kita. Apakah ada solusi yang baik untuk diterapkan INotifyPropertyChanged
di kelas Anda atau satu-satunya cara untuk melakukannya adalah dengan meningkatkan PropertyChanged
acara di setiap properti.
Jika tidak, bisakah kita menulis sesuatu untuk menghasilkan potongan kode secara otomatis untuk meningkatkan PropertyChanged
acara?
Jawaban:
Tanpa menggunakan sesuatu seperti postsharp, versi minimal yang saya gunakan menggunakan sesuatu seperti:
Setiap properti kemudian hanya sesuatu seperti:
yang tidak besar; itu juga dapat digunakan sebagai kelas dasar jika Anda mau. The
bool
kembali dariSetField
memberitahu Anda jika itu adalah no-op, jika Anda ingin menerapkan logika lain.atau lebih mudah dengan C # 5:
yang bisa disebut seperti ini:
dengan mana kompiler akan menambahkan
"Name"
secara otomatis.C # 6.0 membuat implementasi lebih mudah:
... dan sekarang dengan C # 7:
sumber
[CallerMemberName]
Pada .Net 4.5 akhirnya ada cara mudah untuk melakukan ini.
.Net 4.5 memperkenalkan Atribut Informasi Penelepon baru.
Mungkin juga merupakan ide bagus untuk menambahkan pembanding ke fungsi tersebut.
Lebih banyak contoh di sini dan di sini
Juga lihat Informasi Penelepon (C # dan Visual Basic)
sumber
Saya sangat suka solusi Marc, tapi saya pikir itu bisa sedikit ditingkatkan untuk menghindari menggunakan "string ajaib" (yang tidak mendukung refactoring). Alih-alih menggunakan nama properti sebagai string, lebih mudah menjadikannya ekspresi lambda:
Cukup tambahkan metode berikut ke kode Marc, itu akan melakukan trik:
BTW, ini terinspirasi oleh
posting blog iniURL yang diperbaruisumber
Ada juga Fody yang memiliki add-in PropertyChanged , yang memungkinkan Anda menulis ini:
... dan pada waktu kompilasi menyuntikkan pemberitahuan properti yang diubah.
sumber
"Fody/.*?:",LogCustom2,True
menyoroti dalam warna "Custom 2". Saya membuatnya merah muda cerah sehingga mudah ditemukan. Hanya Fody segalanya, ini adalah cara paling rapi untuk melakukan apa pun yang memiliki banyak pengetikan berulang.Saya pikir orang harus lebih memperhatikan kinerja; itu benar-benar berdampak pada UI ketika ada banyak objek untuk diikat (bayangkan sebuah grid dengan 10.000 baris), atau jika nilai objek sering berubah (aplikasi pemantauan real-time).
Saya mengambil berbagai implementasi yang ditemukan di sini dan di tempat lain dan melakukan perbandingan; lihat perbandingan kinerja implementasi INotifyPropertyChanged .
Berikut ini intip hasilnya
sumber
Saya memperkenalkan kelas Bindable di blog saya di http://timoch.com/blog/2013/08/annoyed-with-inotifypropertychange/ Bindable menggunakan kamus sebagai tas properti. Cukup mudah untuk menambahkan kelebihan yang diperlukan untuk subkelas untuk mengelola bidang dukungannya sendiri menggunakan parameter ref.
Kode:
Dapat digunakan seperti ini:
sumber
protected T Get<T>(T defaultValue, [CallerMemberName] string name = null)
dan juga memeriksaif (_properties.ContainsKey(name) && Equals(value, Get<T>(default(T), name)))
di Set (untuk meningkatkan & menyimpan ketika pertama kali diatur ke nilai default)Saya belum benar-benar memiliki kesempatan untuk mencobanya sendiri, tetapi lain kali saya membuat proyek dengan persyaratan besar untuk INotifyPropertyChanged Saya berniat menulis atribut Postsharp yang akan menyuntikkan kode pada waktu kompilasi. Sesuatu seperti:
Akan menjadi:
Saya tidak yakin apakah ini akan berhasil dalam praktek dan saya perlu duduk dan mencobanya, tetapi saya tidak mengerti mengapa tidak. Saya mungkin perlu membuatnya menerima beberapa parameter untuk situasi di mana lebih dari satu OnPropertyChanged perlu dipicu (jika, misalnya, saya memiliki properti FullName di kelas di atas)
Saat ini saya menggunakan template khusus di Resharper, tetapi bahkan dengan itu saya sudah muak dengan semua properti saya yang begitu lama.
Ah, pencarian Google cepat (yang seharusnya saya lakukan sebelum saya menulis ini) menunjukkan bahwa setidaknya satu orang telah melakukan sesuatu seperti ini sebelumnya sini . Tidak persis apa yang ada dalam pikiran saya, tetapi cukup dekat untuk menunjukkan bahwa teorinya baik.
sumber
Ya, cara yang lebih baik tentu ada. Ini dia:
Tutorial langkah demi langkah menyusut oleh saya, berdasarkan ini artikel yang bermanfaat ini .
NotifierInterceptor
ProxyCreator
-
Masukkan binding ke dalam xaml:
Masukkan baris kode dalam file kode-belakang MainWindow.xaml.cs seperti ini:
DataContext = ProxyCreator.MakeINotifyPropertyChanged<MainViewModel>();
Perhatian!!! Semua properti yang dibatasi harus dihiasi dengan kata kunci virtual karena mereka digunakan oleh proxy castle untuk menimpa.
sumber
type
,interfaces to apply
,interceptors
.CreateClassProxy<T>
metode generik . Jauh berbeda ... hmmm, bertanya-tanya mengapa begitu terbatas dengan metode generik. :(Pendekatan yang sangat mirip AOP adalah menyuntikkan barang-barang INotifyPropertyChanged ke objek yang sudah dipakai dengan cepat. Anda dapat melakukan ini dengan sesuatu seperti Castle DynamicProxy. Berikut ini adalah artikel yang menjelaskan teknik ini:
Menambahkan INotifyPropertyChanged ke objek yang ada
sumber
Lihat di sini: http://dotnet-forum.de/blogs/thearchitect/archive/2012/11/01/die-optimale-implementierung-des-inotifypropertychanged-interfaces.aspx
Ini ditulis dalam bahasa Jerman, tetapi Anda dapat mengunduh ViewModelBase.cs. Semua komentar dalam File cs ditulis dalam Bahasa Inggris.
Dengan ViewModelBase-Class ini dimungkinkan untuk mengimplementasikan properti bindable yang mirip dengan Properti Ketergantungan yang terkenal:
sumber
Berdasarkan jawaban oleh Thomas yang diadaptasi dari jawaban oleh Marc, saya telah mengubah kode perubahan properti yang direfleksikan menjadi kelas dasar:
Penggunaannya sama dengan jawaban Thomas kecuali Anda dapat memberikan properti tambahan untuk diberitahukan. Ini diperlukan untuk menangani kolom terhitung yang perlu di-refresh dalam kotak.
Saya punya ini mengemudi koleksi item yang disimpan di BindingList terbuka melalui DataGridView. Ini telah menghilangkan kebutuhan saya untuk melakukan panggilan Refresh () manual ke grid.
sumber
Biarkan saya memperkenalkan pendekatan saya sendiri yang disebut Yappi . Itu milik generator kelas turunan proxy Runtime |, menambahkan fungsionalitas baru ke objek atau tipe yang ada, seperti Proxy Dinamis dari Caste Project.
Ini memungkinkan untuk mengimplementasikan INotifyPropertyChanged sekali di kelas dasar, dan kemudian mendeklarasikan kelas turunan dengan gaya berikut, masih mendukung INotifyPropertyChanged untuk properti baru:
Kompleksitas kelas turunan atau konstruksi proxy dapat disembunyikan di belakang baris berikut:
Dan semua pekerjaan implementasi INotifyPropertyChanged dapat dilakukan seperti ini:
Ini sepenuhnya aman untuk refactoring, tidak menggunakan pantulan setelah konstruksi tipe dan cukup cepat.
sumber
TDeclaration
mengetikkan parameterPropertyImplementation
? Tentunya Anda dapat menemukan tipe yang tepat untuk memanggil (bukan callvirt) pengambil / penyetel hanya denganTImplementation
?Semua jawaban ini sangat bagus.
Solusi saya menggunakan cuplikan kode untuk melakukan pekerjaan.
Ini menggunakan panggilan paling sederhana ke acara PropertyChanged.
Simpan cuplikan ini dan gunakan saat Anda menggunakan cuplikan 'fullprop'.
Anda dapat memodifikasi panggilan sesuka Anda (untuk menggunakan solusi di atas)
sumber
Jika Anda menggunakan dinamika di .NET 4.5, Anda tidak perlu khawatir
INotifyPropertyChanged
.jika Name terikat ke beberapa kontrol, itu hanya berfungsi dengan baik.
sumber
Solusi gabungan lainnya menggunakan StackFrame:
Pemakaian:
sumber
get_Foo
metode dalam mode Release.Saya membuat Metode Ekstensi di Perpustakaan basis saya untuk digunakan kembali:
Ini berfungsi dengan .Net 4.5 karena CallerMemberNameAttribute . Jika Anda ingin menggunakannya dengan versi .Net yang lebih lama, Anda harus mengubah deklarasi metode dari:
...,[CallerMemberName] string propertyName = "", ...
menjadi...,string propertyName, ...
Pemakaian:
sumber
Saya memutuskan dengan cara ini (ini sedikit laboriouse, tapi itu pasti lebih cepat di runtime).
Di VB (maaf, tapi saya pikir tidak sulit menerjemahkannya dalam C #), saya membuat substitusi ini dengan RE:
dengan:
Ini transofrm semua kode seperti ini:
Di
Dan Jika saya ingin memiliki kode yang lebih mudah dibaca, saya bisa sebaliknya hanya membuat substitusi berikut:
Dengan
Saya membuang untuk mengganti kode IL dari metode yang ditetapkan, tetapi saya tidak bisa menulis banyak kode yang dikompilasi di IL ... Jika suatu hari saya menulisnya, saya akan mengatakan Anda!
sumber
Saya menyimpan ini sebagai potongan. C # 6 menambahkan beberapa sintaks yang bagus untuk memanggil pawang.
sumber
Berikut adalah NotifyPropertyChanged versi Unity3D atau non-CallerMemberName
Kode ini memungkinkan Anda untuk menulis bidang dukungan properti seperti ini:
Selain itu, dalam pengambilan ulang jika Anda membuat potongan pola / pencarian, Anda kemudian dapat juga mengotomatiskan alur kerja Anda dengan mengonversi bidang prop sederhana menjadi dukungan di atas.
Pola pencarian:
Ganti Pola:
sumber
Saya telah menulis artikel yang membantu ini ( https://msdn.microsoft.com/magazine/mt736453 ). Anda dapat menggunakan paket NuGet SolSoft.DataBinding. Maka Anda dapat menulis kode seperti ini:
Manfaat:
sumber
Walaupun jelas ada banyak cara untuk melakukan ini, dengan pengecualian jawaban sihir AOP, tidak ada jawaban yang tampaknya melihat pengaturan properti Model langsung dari model tampilan tanpa memiliki bidang lokal untuk referensi.
Masalahnya adalah Anda tidak dapat mereferensikan properti. Namun, Anda bisa menggunakan Action untuk menyetel properti itu.
Ini dapat digunakan seperti ekstrak kode berikut.
Lihat repo BitBucket ini untuk implementasi penuh metode dan beberapa cara berbeda untuk mencapai hasil yang sama, termasuk metode yang menggunakan LINQ dan metode yang menggunakan refleksi. Perhatikan bahwa metode ini lebih lambat kinerjanya.
sumber
Hal-hal lain yang mungkin ingin Anda pertimbangkan ketika menerapkan sifat-sifat ini adalah kenyataan bahwa INotifyPropertyChang * ed * ing keduanya menggunakan kelas argumen acara.
Jika Anda memiliki sejumlah besar properti yang sedang disetel maka jumlah instance kelas argumen event bisa sangat besar, Anda harus mempertimbangkan untuk menyimpannya karena itu adalah salah satu area yang dapat terjadi ledakan string.
Lihatlah implementasi ini dan penjelasan mengapa itu dikandung.
Josh Smiths Blog
sumber
Saya baru saja menemukan ActiveSharp - Automatic INotifyPropertyChanged , saya belum menggunakannya, tetapi terlihat bagus.
Mengutip dari situs webnya ...
Alih-alih, tulis properti seperti ini:
Perhatikan bahwa tidak perlu menyertakan nama properti sebagai string. ActiveSharp secara andal dan benar memperkirakan hal itu untuk dirinya sendiri. Ini bekerja berdasarkan fakta bahwa implementasi properti Anda melewati bidang dukungan (_foo) oleh ref. (ActiveSharp menggunakan panggilan "by ref" untuk mengidentifikasi bidang dukungan mana yang dilewati, dan dari bidang itu mengidentifikasi properti).
sumber
Sebuah ide menggunakan refleksi:
sumber
Saya menyadari pertanyaan ini sudah memiliki trilyun jawaban, tetapi tidak satupun dari mereka merasa cukup tepat untuk saya. Masalah saya adalah saya tidak ingin ada hit kinerja dan saya mau tahan dengan sedikit kata-kata kasar untuk alasan itu saja. Saya juga tidak terlalu peduli untuk properti otomatis, yang membawa saya ke solusi berikut:
Dengan kata lain, solusi di atas nyaman jika Anda tidak keberatan melakukan ini:
Pro
Cons
Sayangnya, masih lebih baik daripada melakukan ini,
Untuk setiap properti, yang menjadi mimpi buruk dengan verbositas tambahan ;-(
Catatan, saya tidak mengklaim solusi ini lebih baik dari segi kinerja dibandingkan dengan yang lain, hanya saja itu adalah solusi yang layak bagi mereka yang tidak menyukai solusi lain yang disajikan.
sumber
Saya datang dengan kelas dasar ini untuk menerapkan pola yang dapat diamati, cukup banyak melakukan apa yang Anda butuhkan ( "secara otomatis" menerapkan set dan dapatkan). Saya menghabiskan satu jam pada ini sebagai prototipe, jadi tidak memiliki banyak unit test, tetapi membuktikan konsepnya. Catatan itu menggunakan
Dictionary<string, ObservablePropertyContext>
untuk menghapus kebutuhan untuk bidang pribadi.Ini penggunaannya
sumber
Saya sarankan untuk menggunakan ReactiveProperty. Ini adalah metode terpendek kecuali Fody.
sebagai gantinya
( DOCS )
sumber
Ide lain ...
sumber
=> di sini solusi saya dengan fitur-fitur berikut
sumber
Gunakan ini
}
sumber