INotifyPropertyChanged vs DependencyProperty di ViewModel

353

Ketika menerapkan ViewModel dalam arsitektur Model-View-ViewModel aplikasi WPF tampaknya ada dua pilihan utama bagaimana membuatnya menjadi dataable. Saya telah melihat implementasi yang digunakan DependencyPropertyuntuk properti yang akan diikat oleh View dan saya telah melihat implementasi ViewModel INotifyPropertyChangedsebagai gantinya.

Pertanyaan saya adalah kapan saya harus memilih yang satu daripada yang lain? Apakah ada perbedaan kinerja? Apakah benar-benar ide yang baik untuk memberikan dependensi ViewModel ke WPF? Apa lagi yang perlu saya pertimbangkan ketika membuat keputusan desain?

bitbonk
sumber
11
lihat stackoverflow.com/questions/1329138/... untuk kompiler yang memeriksa cara mengimplementasikan INotifyPropertyChanged. Menghindari memiliki nama properti sebagai string ajaib.
Ian Ringrose
10
Secara umum ada perbedaan besar antara properti dependensi dan properti normal di kelas yang mengimplementasikan INotifyPropertyChanged. Properti ketergantungan dapat menjadi sumber atau target dalam pengikatan data tetapi properti normal dengan dukungan INotifyPropertyChanged dapat digunakan sebagai sumber saja. Jadi solusi ini tidak sepenuhnya dapat dipertukarkan. Infrastruktur pengikat data membutuhkan DP sebagai target untuk bekerja, tetapi sumbernya dapat berupa properti normal dengan dukungan INotifyPropertyChanged atau DP umum.
Mostafa Rezaei
4
Lihat stackoverflow.com/a/10595688/200442 untuk cara penerapan .net 4.5 INotifyPropertyChanged.
Daniel Little
paling baik dijelaskan di sini stackoverflow.com/a/3552550/366064
Bizhan

Jawaban:

214

Kent menulis blog yang menarik tentang topik ini: Lihat Model: POCO versus DependencyObjects .

Ringkasan singkat:

  1. DependencyObjects tidak ditandai sebagai serializable
  2. Kelas DependencyObject menimpa dan menyegel metode Equals () dan GetHashCode ()
  3. DependencyObject memiliki afinitas utas - ia hanya dapat diakses pada utas tempat ia dibuat

Saya lebih suka pendekatan POCO. Kelas dasar untuk PresentationModel (alias ViewModel) yang mengimplementasikan antarmuka INotifyPropertyChanged dapat ditemukan di sini: http://compositeextensions.codeplex.com

jbe
sumber
24
DependencyObject juga membutuhkan ketergantungan pada pustaka WPF, sedangkan POCO tidak, memungkinkan model tampilan Anda menggerakkan beberapa tumpukan UI lain di mana WPF tidak tersedia (Compact Framework, Mono).
codekaizen
26
Maka jelas, bahwa Properti Ketergantungan semata-mata dibangun untuk UI dan bukan untuk lapisan bisnis.
Andrei Rînea
11
Properti Ketergantungan juga memerlukan induk DependencyObject. ViewModel Anda seharusnya tidak mewarisi dari DependencyObject.
Gusdor
38

Menurut panduan kinerja WPF, DependencyObjects jelas berkinerja lebih baik daripada POCO yang menerapkan INotifyPropertyChanged:

http://msdn.microsoft.com/en-us/library/bb613546.aspx

James Ashley
sumber
1
Saya harus menyetujui yang satu itu ;-): blog.lexique-du-net.com/index.php?post/2010/02/24/…
Jonatha ANTOINE
Jika Anda memilih .NET Framework versi 4, maka tautannya masih berfungsi. Hanya saja tidak tersedia untuk "versi saat ini".
gandakan kamu
Terima kasih telah menunjukkan ini, ada banyak kesalahan informasi yang memalukan di luar sana dari para pengembang yang membuat pernyataan cabul bahwa INotifyPropertyChanged lebih cepat atau mengeluarkan biaya lebih sedikit daripada DP dan itu tidak berdasar. DP adalah cara cepat, elegan dan kuat untuk secara struktural mendefinisikan pohon virtual (data).
tpartee
Ada iblis tersembunyi untuk DependencyObjects. Mereka harus dibuat di utas yang sama dengan kontrol yang mengikatnya. Itu berarti utas GUI. Itu berarti Anda harus mengirim kreasi ke utas itu. Misalnya, Anda tidak dapat memuat dan membuat beberapa utas latar belakang dari DB. Kecuali Anda mengirim ciptaan. Gila.
ed22
28

Pilihannya sepenuhnya didasarkan pada logika bisnis dan tingkat abstraksi UI Anda. Jika Anda tidak ingin pemisahan yang baik maka DP akan bekerja untuk Anda.

DependencyProperties akan berlaku terutama di tingkat VisualElements sehingga tidak akan menjadi ide bagus jika kita membuat banyak DP untuk masing-masing persyaratan bisnis kita. Juga ada biaya yang lebih besar untuk DP daripada INotifyPropertyChanged. Ketika Anda mendesain WPF / Silverlight, cobalah untuk merancang UI dan ViewModel yang benar-benar terpisah sehingga pada suatu titik waktu kami dapat mengubah tata letak dan kontrol UI (Berdasarkan tema dan Gaya)

Lihat posting ini juga - /programming/275098/what-applications-could-i-study-to-understand-datamodel-view-view-viewmodel . Tautan ini memiliki banyak referensi ke pola Model-View-ViewModel, yang sangat relevan dengan diskusi ini.

Jobi Joy
sumber
9
Posting oleh jbe menjawab perbedaan lebih akurat. Hanya karena VM (atau Presenter) mewarisi dari DependencyObject tidak berarti bahwa itu tidak dapat ditata atau tidak secara logis terpisah dari View, itu hanya berarti bahwa penyimpanan untuk nilai properti berbeda dari bidang yang dinyatakan secara eksplisit di bidang Gaya POCO. Karena itu, serialisasi, kesetaraan logis, dan afinitas utas adalah masalah nyata yang harus dihadapi oleh DepsencyObject berbasis VM.
micahtan
"Juga ada biaya yang lebih besar untuk DP daripada INotifyPropertyChanged" - di mana sumber pembuktian Anda tentang ini? Banyak pengembang membuat klaim ini tanpa bukti yang mendukungnya. Menurut MSDN itu tidak benar. "cobalah untuk mendesain UI dan ViewModel yang benar-benar terpisah sehingga pada suatu saat kita dapat mengubah kontrol Layout dan UI" - sekali lagi, ini sama sekali tidak ada hubungannya dengan POCO + PropChange versus DO / DP. Jika ada, registri Reflection dan Path di DO / DP meningkatkan kemampuan Anda untuk bekerja di sisi visual.
tpartee
20

Dari sudut pandang ekspresif, saya benar-benar menikmati menggunakan properti ketergantungan dan ngeri pada pemikiran INotifyPropertyChanged. Terlepas dari stringnama properti dan kemungkinan kebocoran memori karena berlangganan acara, INotifyPropertyChangedadalah mekanisme yang jauh lebih eksplisit.

Ketergantungan properti menyiratkan "saat ini, lakukan itu" menggunakan metadata statis yang mudah dipahami. Ini adalah pendekatan deklaratif yang mendapatkan suara saya untuk keanggunan.

Bryan Watts
sumber
1
Bagian string sekarang memiliki solusi dengan nama operator.
Newtopian
@Newtopian: Benar. Ada juga beberapa hal menarik yang mungkin dilakukan [CallerMemberName].
Bryan Watts
Belum lagi kekayaan manfaat Pendaftaran Properti (Refleksi) di WPF dan CLR ketika menggunakan model DO / DP versus POCO.
tpartee
16

INotifyPropertyChanged ketika digunakan juga memberi Anda kemampuan untuk menambahkan lebih banyak logika dalam kode pengambil dan penyetel properti Anda.

DependencyProperty contoh:

public static DependencyProperty NameProperty = DependencyProperty.Register( "Name", typeof( String), typeof( Customer ) );

public String Name
{
    set { SetValue( NameProperty, value ); }
    get { return ( String ) GetValue( NameProperty ); }
}

Dalam pengambil dan penyetel Anda --- yang dapat Anda lakukan hanyalah memanggil SetValue dan GetValue masing-masing, b / c di bagian lain dari kerangka pengambil / penyetel tidak dipanggil, alih-alih secara langsung memanggil SetValue, GetValue, sehingga logika properti Anda tidak akan dieksekusi dengan andal.

Dengan INotifyPropertyChanged, tentukan acara:

public event PropertyChangedEventHandler PropertyChanged;

Dan kemudian cukup sediakan logika apa pun di dalam kode Anda, lalu panggil:

// ...
// Something cool...
// ...

if( this.PropertyChanged != null )
{
    PropertyChanged( this, new PropertyChangedEventArgs( "Name" ) );
}

// More cool stuff that will reliably happen...

Ini bisa dalam pengambil / penyetel, atau di tempat lain.

Adam
sumber
11
Anda bisa mendapatkan notifikasi perubahan dari DependencyProperties juga. Lihat PropertyMetadata.PropertyChangedCallback. Contoh di: msdn.microsoft.com/en-us/library/ms745795.aspx
Joe White
2
Juga, Anda dapat memanggil SetValue dari mana saja juga, tidak hanya dari dalam properti
aL3891
Ini menyesatkan dan tidak benar - ada banyak cara untuk menghubungkan perubahan acara di DP, bahkan ketika itu diubah 'secara internal'. Salah satunya ditunjukkan di atas oleh Joe White
penerima kartu
16

Properti ketergantungan dimaksudkan untuk mendukung pengikatan (sebagai target) pada elemen UI bukan sebagai sumber pengikatan data, ini adalah tempat INotifyProperty masuk. Dari sudut pandang murni Anda tidak boleh menggunakan DP pada ViewModels.

"Untuk menjadi sumber ikatan, properti tidak perlu menjadi properti dependensi; Anda dapat menggunakan properti CLR sebagai sumber mengikat. Namun, untuk menjadi target dari ikatan, properti harus menjadi properti ketergantungan. Agar pengikatan satu arah atau dua arah menjadi efektif, properti sumber harus mendukung pemberitahuan perubahan yang menyebar ke sistem pengikatan dan dengan demikian target. Untuk sumber pengikatan CLR kustom, ini berarti bahwa properti tersebut harus mendukung INotifyPropertyChanged. Koleksi harus mendukung INotifyCollectionChanged. "

Semua objek ketergantungan tidak dapat diserialisasi (Ini bisa menghambat penggunaan ViewModels dan DTO (POCO).

Ada perbedaan antara DP dalam Silverlight dibandingkan dengan WPF.

http://msdn.microsoft.com/en-us/library/cc221408(v=VS.95).aspx

http://msdn.microsoft.com/en-us/library/cc903933(VS.95).aspx

Nick Hermans
sumber
Saya telah menggunakan Objek Ketergantungan serial sejak 2009 tanpa masalah, jadi tidak yakin apa yang Anda bicarakan ketika Anda mengatakan "Semua objek ketergantungan tidak dapat diserialisasi" - ya mereka bisa. Bahkan ada banyak pilihan: codeproject.com/Articles/61440/... emphess.net/2008/11/25/dependencyproperty-serialization Dan salah satu favorit pribadi saya: hanya memberikan dukungan toko untuk semua DP Anda dan membuat Serializable mereka ( tidak ada contoh sederhana yang baik tersedia dalam 2 menit pencarian di Google, tapi saya jamin ini berhasil).
tpartee
7

Saya juga harus mempertimbangkan keputusan ini baru-baru ini.

Saya menemukan bahwa mekanisme INotifyPropertyChanged cocok dengan kebutuhan saya lebih baik karena memungkinkan saya untuk menempelkan GUI ke kerangka kerja logika bisnis yang ada tanpa status duplikasi. Kerangka kerja yang saya gunakan memiliki pola pengamat sendiri dan mudah untuk meneruskan satu tingkat pemberitahuan ke yang berikutnya. Saya hanya punya kelas yang mengimplementasikan antarmuka pengamat dari kerangka kerja logika bisnis saya dan antarmuka INotifyPropertyChanged.

Dengan DP Anda tidak dapat menentukan backend yang menyimpan negara sendiri. Saya harus membiarkan .net cache salinan setiap item negara saya mengikat. Ini seperti overhead yang tidak perlu - kondisi saya besar dan rumit.

Jadi di sini saya menemukan INotifyPropertyChanged lebih baik untuk mengekspos properti dari logika bisnis ke GUI.

Itu dikatakan di mana saya membutuhkan widget GUI khusus untuk mengekspos sebuah properti dan untuk perubahan pada properti itu untuk mempengaruhi widget GUI lainnya, DP membuktikan solusi sederhana.

Jadi di sana saya menemukan DP berguna untuk notifikasi GUI ke GUI.

morechilli
sumber
6

Apakah benar-benar ide yang baik untuk memberikan dependensi ViewModel ke WPF?

.NET 4.0 akan memiliki System.Xaml.dll, jadi Anda tidak perlu lagi bergantung pada kerangka kerja sewenang-wenang untuk menggunakannya. Lihat posting Rob Relyea tentang sesi PDC-nya.

Saya ambil

XAML adalah bahasa untuk mendeskripsikan objek, dan WPF adalah kerangka kerja yang menggambarkan objek adalah elemen UI.

Hubungan mereka mirip dengan C #, bahasa untuk menggambarkan logika, dan .NET, suatu kerangka kerja yang mengimplementasikan jenis logika tertentu.

Tujuan XAML adalah grafik objek deklaratif. Teknologi W * F adalah kandidat yang bagus untuk paradigma ini, tetapi XAML ada secara independen dari mereka.

XAML dan seluruh sistem ketergantungan diimplementasikan sebagai tumpukan terpisah untuk WF dan WPF, mungkin untuk meningkatkan pengalaman tim yang berbeda tanpa menciptakan ketergantungan (tidak ada permainan kata-kata) di antara mereka.

Bryan Watts
sumber
Dengan menjawab, Anda tampaknya membuat asumsi bahwa bitbonk menganggap XAML dan WPF sama. ViewModels harus memiliki ketergantungan WPF sesedikit mungkin, bukan untuk meningkatkan pemisahan logis, tetapi untuk mengurangi kompleksitas kode dan menghindari semua masalah yang terkait dengan hanya menulis logika dalam kode-belakang kontrol pengguna. Anda pasti akan menerapkan konsep-konsep WPF seperti ICommand dan menunjukkan perilaku yang hanya WPF / Silverlight yang dapat membungkus dengan mudah - satu-satunya masalah presentasi Anda dalam model tampilan adalah CollectionViews dan ObservableCollection.
Gusdor
6

Ketergantungan properti adalah perekat pembuatan kontrol kustom. Jika Anda tertarik menggunakan Intelli-sense untuk menunjukkan properti Anda di jendela properti pada waktu desain XAML, Anda harus menggunakan properti Ketergantungan. INPC tidak akan pernah menampilkan properti di jendela properti pada waktu desain.

John Peters
sumber
4

Tampaknya Properti Ketergantungan harus digunakan dalam kontrol yang Anda buat seperti Tombol. Untuk menggunakan properti di XAML dan menggunakan semua fitur WPF, properti tersebut harus Dependency Properties.

Namun, ViewModel Anda lebih baik menggunakan INotifyPropertyChanged. Menggunakan INotifyPropertyChanged akan memberi Anda kemampuan untuk memiliki logika pengambil / penyetel jika perlu.

Saya sarankan memeriksa versi Josh Smith dari kelas dasar untuk ViewModel yang sudah mengimplementasikan INotifyPropertyChanged:

http://joshsmithonwpf.wordpress.com/2007/08/29/a-base-class-which-implements-inotifypropertychanged/

Saya pikir ini adalah contoh yang bagus tentang cara melakukan ViewModel.

timothymcgrath
sumber
4

Saya pikir DependencyProperty dan INotifyPropertyChanged digunakan untuk dua hal berbeda di Binding: yang pertama untuk memungkinkan properti menjadi target pengikatan dan menerima input dari properti lain (gunakan {Binding ...} untuk mengatur properti), yang terakhir saat Anda ingin nilai properti digunakan sebagai sumber pengikatan (nama dalam Ekspresi Jalur Binding). Jadi pilihannya hanyalah teknis.

Domnik
sumber
2
INotifyPropertyChanged dapat digunakan dalam kedua kasus tersebut. Anda dapat mengikat TwoWay untuk itu. DependencyProperty diperlukan karena alasan teknis hanya untuk beberapa tindakan yang dilakukan pada objek View (mengatur beberapa properti saat instantiating objek View di XAML, misalnya). DependencyProperty tidak pernah diperlukan untuk ViewModel.
oillio
3

Saya lebih suka pendekatan yang lebih langsung, yang saya blogging tentang dalam Model Presentasi Tanpa INotifyPropertyChanged . Menggunakan alternatif untuk pengikatan data, Anda dapat mengikat langsung ke properti CLR tanpa kode pembukuan. Anda hanya menulis kode .NET tua-polos di Model Tampilan Anda, dan itu diperbarui ketika Model Data Anda berubah.

Michael L Perry
sumber
Tanpa INotifyPropertyChanged, PropertyDescriptordigunakan, yang menyebabkan kebocoran memori
Tilak
Pustaka Kontrol Kontrol yang saya sajikan dalam posting blog menggunakan referensi yang lemah, bukan deskriptor properti. Itu tidak bocor memori.
Michael L Perry
1
Michael, perpustakaan Anda menghasilkan banyak kode. Saya tidak melihat manfaatnya. Saya dapat mencapai hal yang sama dengan membuat bungkus model dengan panggilan acara PropertyChanged yang dihasilkan.
Der_Meister
3

Hanya ada satu hal mengapa memilih DependencyObject- Mengikat akan bekerja lebih baik. Coba saja contoh dengan ListBoxdan TextBox, isi daftar dengan data dari INotifyPropertyChangedproperti vs. DependencyPropertydan edit item saat ini dari TextBox...

ramos
sumber
1
Contoh kode, silakan
Hassan Tareq
1

Jika Anda ingin mengekspos properti ke kontrol lain, Anda harus menggunakan properti Ketergantungan ... Tapi semoga berhasil karena butuh waktu untuk mencari tahu ...

JWP
sumber