Dalam MVVM haruskah ViewModel atau Model mengimplementasikan INotifyPropertyChanged?

165

Kebanyakan contoh MVVM yang telah saya kerjakan memiliki penerapan ModelINotifyPropertyChanged , tetapi dalam contoh CommandSink Josh Smith mengimplementasikan ViewModelINotifyPropertyChanged .

Saya masih secara kognitif menyusun konsep MVVM, jadi saya tidak tahu apakah:

  • Anda harus meletakkan INotifyPropertyChanged di ViewModel untuk mulai CommandSinkbekerja
  • Ini hanyalah penyimpangan dari norma dan itu tidak terlalu penting
  • Anda harus selalu menerapkan Model INotifyPropertyChanged dan ini hanyalah kesalahan yang akan diperbaiki jika ini dikembangkan dari contoh kode ke aplikasi

Apa pengalaman orang lain tentang proyek MVVM yang telah Anda kerjakan?

Edward Tanguay
sumber
4
jika Anda menerapkan INPC, cobalah github.com/Fody/PropertyChanged - ini akan menghemat waktu Anda mengetik selama beberapa minggu.
CAD cowok

Jawaban:

104

Saya akan mengatakan sebaliknya, saya selalu memakai INotifyPropertyChangedViewModel saya - Anda benar-benar tidak ingin mencemari model Anda dengan fitur spesifik WPF sepertiINotifyPropertyChanged , barang-barang itu harus berada di ViewModel.

Saya yakin orang lain akan tidak setuju, tetapi itulah cara saya bekerja.

Steven Robbins
sumber
84
Apa yang Anda lakukan jika suatu properti berubah dalam model? Anda perlu membawanya ke model tampilan entah bagaimana. Pertanyaan jujur, saya sedang berurusan dengan teka-teki ini sekarang.
Roger Lipscombe
4
EventAggregator dalam kode Prism adalah alternatif yang baik untuk INotifyPropertyChanged pada model, dengan properti ubahsuaian jenis acara. Kode peristiwa dalam proyek itu mendukung peristiwa penerusan antara latar belakang dan utas UI, yang terkadang bisa menjadi masalah.
Steve Mitcham
51
INotifyProperyChanged bukan WPF spesifik, ia tinggal di System.ComponentModel namespace, saya telah menggunakannya dalam aplikasi WinForms, juga INotifyPropertyChanged telah ada di. Net sejak 2.0, WPF hanya ada sejak 3.0
benPearce
40
Saya penggemar menempatkan INotifyPropertyChanged di MODEL dan VIEWMODEL. Saya tidak bisa memikirkan alasan untuk tidak melakukan ini. Ini cara yang elegan untuk menginformasikan VIEWMODEL tentang kapan perubahan latar belakang telah terjadi dalam MODE Anda yang memengaruhi VIEWMODEL sama seperti yang digunakan untuk menginformasikan VIEWMODEL dan telah ada perubahan pada VIEWMODEL.
ScottCher
6
@Steve - tentang memberi tahu ViewModel bahwa properti Model telah berubah, sepertinya INotifyPropertyChanged berfungsi dengan baik sebagai "peristiwa yang dapat dimasuki viewmodel". Kenapa tidak menggunakannya?
skybluecodeflier
146

Saya sangat tidak setuju dengan konsep bahwa Model seharusnya tidak menerapkan INotifyPropertyChanged. Antarmuka ini bukan khusus UI! Ini hanya menginformasikan perubahan. Memang, WPF banyak menggunakan ini untuk mengidentifikasi perubahan, tetapi itu tidak berarti itu adalah antarmuka UI. Saya akan membandingkannya dengan komentar berikut: " Ban adalah aksesori mobil ". Tentu saja, tetapi sepeda, bus, dll juga menggunakannya. Singkatnya, jangan menganggap antarmuka itu sebagai hal UI.

Karena itu, itu tidak berarti saya percaya bahwa Model harus memberikan pemberitahuan. Bahkan, sebagai aturan praktis, model tidak harus mengimplementasikan antarmuka ini, kecuali jika diperlukan.Dalam kebanyakan kasus di mana tidak ada data server didorong ke aplikasi klien, modelnya bisa basi. Tetapi jika mendengarkan data pasar keuangan, maka saya tidak melihat mengapa model tidak dapat mengimplementasikan antarmuka. Sebagai contoh, bagaimana jika saya memiliki logika non-UI seperti layanan yang ketika menerima tawaran atau harga Permintaan untuk nilai yang diberikan itu mengeluarkan peringatan (mis. Melalui email) atau memesan? Ini bisa menjadi solusi bersih yang mungkin.

Namun, ada berbagai cara untuk mencapai hal-hal, tetapi saya selalu berdebat demi kesederhanaan dan menghindari redundansi.

Apa yang lebih baik Mendefinisikan peristiwa pada koleksi atau perubahan properti pada model tampilan dan menyebarkannya ke model atau meminta tampilan memperbarui model secara intrinsik (melalui model tampilan)?

Intinya setiap kali Anda melihat seseorang mengklaim bahwa " Anda tidak dapat melakukan ini atau itu " itu adalah tanda mereka tidak tahu apa yang mereka bicarakan.

Itu benar-benar tergantung pada kasus Anda dan pada kenyataannya MVVM adalah kerangka kerja dengan banyak masalah dan saya belum melihat implementasi umum MVVM di seluruh papan.

Saya berharap saya memiliki lebih banyak waktu untuk menjelaskan banyak rasa MVVM dan beberapa solusi untuk masalah umum - kebanyakan disediakan oleh pengembang lain, tapi saya rasa saya harus melakukannya lain kali.

Paulo Sousa
sumber
7
Pikirkan seperti ini. Jika Anda, sebagai pengembang mengkonsumsi .dll dengan Models di dalam Anda tentu tidak akan menulis ulang mereka untuk mendukung INotifyPropertyChanged.
Lee Treveil
2
Sangat setuju dengan Anda. Seperti saya, Anda mungkin juga senang mengetahui bahwa dokumentasi MVVM resmi < msdn.microsoft.com/en-us/library/gg405484%28v=pandp.40%29.aspx > (bagian Model) setuju dengan kami. :-)
Noldorin
"Namun, teh adalah cara yang berbeda untuk mencapai sesuatu tetapi saya selalu berdebat demi kesederhanaan dan menghindari redundansi." Sangat penting.
Bastien Vandamme
1
INotifyPropertyChangedadalah bagian dari System.ComponentModelnamespace yang untuk " perilaku run-time dan desain-waktu komponen dan kontrol ". JANGAN GUNAKAN INotifyPropertyChanged dalam Model, hanya di ViewModels. Tautan ke dokumen: docs.microsoft.com/en-us/dotnet/api/system.componentmodel
Igor Popov
1
Posting lama, saya tahu, tapi saya sering kembali ke sana ketika memulai proyek baru menggunakan MVVM. Saya baru-baru ini mulai menerapkan Prinsip Tanggung Jawab Tunggal lebih ketat. Seorang model harus memiliki satu tanggung jawab. Menjadi model. Segera setelah Anda menambahkan INotifyPropertyChanged ke model, itu tidak lagi mengikuti Prinsip Tanggung Jawab Tunggal. Seluruh alasan ViewModel ada adalah untuk membiarkan model menjadi model, untuk membiarkan model memiliki tanggung jawab tunggal.
Rhyous
13

Saya pikir MVVM sangat buruk namanya dan memanggil ViewModel a ViewModel menyebabkan banyak orang kehilangan fitur penting dari arsitektur yang dirancang dengan baik, yang merupakan DataController yang mengontrol data tidak peduli siapa pun yang mencoba menyentuhnya.

Jika Anda menganggap View-Model lebih sebagai DataController dan mengimplementasikan arsitektur di mana DataController Anda adalah satu-satunya item yang menyentuh data, maka Anda tidak akan pernah menyentuh data secara langsung, tetapi selalu menggunakan DataController. DataController berguna untuk UI tetapi tidak hanya untuk UI. Ini untuk lapisan bisnis, lapisan UI, dll ...

DataModel -------- DataController ------ View
                  /
Business --------/

Anda berakhir dengan model seperti ini. Bahkan bisnis hanya boleh menyentuh data menggunakan ViewModel. Maka teka-teki Anda hilang begitu saja.

Rhyous
sumber
3
Itu bagus jika data Anda hanya berubah ketika DataController mengubahnya. Jika data berasal dari database atau data lain yang dapat memberikan jalan lain untuk perubahan, Anda mungkin perlu memiliki cara untuk menginformasikan VIEWMODEL (DataController dalam pola Anda) dan LIHAT ketika itu terjadi. Anda dapat melakukan polling menggunakan DataController atau mendorong dari beberapa proses eksternal ke DataModel Anda dan memungkinkan DataModel Anda untuk mengirim pemberitahuan perubahan ke DataController Anda.
ScottCher
4
Anda benar sekali. Desain patters levelnya sangat tinggi. Sering kali pola desain menuntun Anda untuk melakukan hal-hal yang benar, tetapi kadang-kadang mereka mengubah Anda dengan cara yang salah. Anda seharusnya tidak pernah menghindari melakukan sesuatu yang benar karena itu di luar pola desain Anda.
Rhyous
Anda juga akan mendorong ke DataController Anda karena kontrol dan model data dan akan memberitahu itu untuk diperbarui.
Rhyous
Juga, Model dalam MVVM harus dijaga spesifik sesuai kebutuhan oleh UI (misalnya DTO). Jadi setiap DB atau logika bisnis yang kompleks harus terjadi di lapisan yang berbeda, dan kemudian data mentah harus disediakan melalui model tampilan.
Nama Kode Jack
9

Itu tergantung pada bagaimana Anda menerapkan model Anda. Perusahaan saya menggunakan objek bisnis yang mirip dengan objek CSLA Lhotka dan memanfaatkan secara luas INotifyPropertyChangedseluruh model bisnis.

Mesin validasi kami sangat bergantung pada pemberitahuan bahwa properti berubah melalui mekanisme ini dan bekerja dengan sangat baik. Jelas, jika Anda menggunakan implementasi berbeda selain objek bisnis di mana pemberitahuan perubahan tidak begitu penting untuk operasi, Anda mungkin memiliki metode lain untuk mendeteksi perubahan dalam model bisnis Anda.

Kami juga memiliki Model Tampilan yang menyebarkan perubahan dari Model jika diperlukan, tetapi Model Tampilan sendiri mendengarkan perubahan Model yang mendasarinya.

Steve Mitcham
sumber
3
Bagaimana tepatnya Anda menyebarkan OnPropertyChanged Model ke OnPropertyChanged ViewModel? Saya punya masalah ketika ViewModel memiliki nama properti yang berbeda dari Model - semacam pemetaan nama-ke-nama akan dibutuhkan, kan?
Martin Konicek
Ini bukan sesuatu yang benar-benar canggih, kami hanya meneruskan acara. Saya kira jika namanya berbeda maka tabel pencarian dapat digunakan. Jika perubahan itu bukan pemetaan satu-ke-satu, maka Anda bisa mengaitkan peristiwa itu dan kemudian memecat peristiwa yang diperlukan di pawang.
Steve Mitcham
6

Saya setuju dengan jawaban Paulo, menerapkan INotifyPropertyChangeddalam Model benar-benar dapat diterima dan bahkan disarankan oleh Microsoft -

Biasanya, model mengimplementasikan fasilitas yang membuatnya mudah untuk mengikat ke tampilan. Ini biasanya berarti mendukung properti dan pengumpulan notifikasi yang diubah melalui INotifyPropertyChangeddan INotifyCollectionChangedantarmuka. Kelas model yang mewakili koleksi objek biasanya berasal dari ObservableCollection<T>kelas, yang menyediakan implementasi INotifyCollectionChangedantarmuka.

Meskipun itu terserah Anda untuk memutuskan apakah Anda ingin jenis implementasi atau tidak, tapi ingat -

Bagaimana jika kelas model Anda tidak mengimplementasikan antarmuka yang diperlukan?

Kadang-kadang Anda akan perlu untuk bekerja dengan model benda-benda yang tidak melaksanakan INotifyPropertyChanged, INotifyCollectionChanged, IDataErrorInfo, atau INotifyDataErrorInfointerface. Dalam kasus tersebut, model tampilan mungkin perlu membungkus objek model dan mengekspos properti yang diperlukan untuk tampilan. Nilai untuk properti ini akan diberikan langsung oleh objek model. Model tampilan akan mengimplementasikan antarmuka yang diperlukan untuk properti yang diekspos sehingga tampilan dapat dengan mudah mengikat data kepada mereka.

Diambil dari - http://msdn.microsoft.com/en-us/library/gg405484(PandP.40).aspx

Saya telah bekerja di beberapa proyek di mana kami belum menerapkan INotifyPropertyChangeddalam model kami dan karena ini kami menghadapi banyak masalah; duplikasi properti yang tidak perlu diperlukan dalam VM dan pada saat yang sama kami harus memperbarui objek yang mendasarinya (dengan nilai yang diperbarui) sebelum meneruskannya ke BL / DL.

Anda akan menghadapi masalah secara khusus jika Anda perlu bekerja dengan koleksi objek model Anda (misalnya dalam kisi atau daftar yang dapat diedit) atau model yang kompleks; objek model tidak akan diperbarui secara otomatis dan Anda harus mengelola semua itu di VM Anda.

akjoshi
sumber
3

Tetapi kadang-kadang (seperti dalam teks tautan presentasi ini ) model adalah layanan, yang memasok aplikasi dengan beberapa data online dan kemudian Anda perlu memastikan pemberitahuan bahwa data baru tiba atau data telah berubah menggunakan acara ...

Andrey Khataev
sumber
3

Saya pikir jawabannya cukup jelas jika Anda ingin mematuhi MV-VM.

lihat: http://msdn.microsoft.com/en-us/library/gg405484(v=PandP.40).aspx

Dalam pola MVVM, tampilan merangkum UI dan logika UI apa pun, model tampilan merangkum logika dan status presentasi, dan model merangkum logika bisnis dan data.

"Tampilan berinteraksi dengan model tampilan melalui pengikatan data, perintah, dan mengubah peristiwa pemberitahuan. Model tampilan meminta, mengamati, dan mengoordinasikan pembaruan untuk model, mengonversi, memvalidasi, dan mengumpulkan data yang diperlukan untuk tampilan dalam tampilan."

John D
sumber
4
Kutipan ini terbuka untuk interpretasi. Saya pikir Anda harus menambahkan interpretasi Anda, untuk membuat jawaban Anda jelas :-)
Søren Boisen
@ John D: Artikel itu hanya memberikan satu interpretasi tentang MVVM dan cara untuk mengimplementasikannya, itu tidak mendefinisikan MVVM.
akjoshi
Selain itu, jika Anda membaca artikel lengkap, ia mendefinisikan kelas Model seperti ini: "Biasanya, model mengimplementasikan fasilitas yang membuatnya mudah untuk mengikat tampilan. Ini biasanya berarti mendukung pemberitahuan pemberitahuan perubahan properti dan koleksi melalui antarmuka INotifyPropertyChanged dan INotifyCollectionChanged Kelas model yang mewakili koleksi objek biasanya berasal dari kelas ObservableCollection <T>, yang menyediakan implementasi antarmuka INotifyCollectionChanged. "
akjoshi
2

Saya akan katakan di ViewModel Anda. Ini bukan bagian dari Model karena Model ini agnostik UI. Model harus 'semuanya KECUALI bisnis agnostik'

Steve Dunn
sumber
2

Menerapkan INPC dalam model dapat digunakan jika model secara jelas terbuka di ViewModel. Tetapi secara umum, ViewModel membungkus model adalah kelasnya sendiri untuk mengurangi kompleksitas model (yang seharusnya tidak berguna untuk penjilidan). Dalam hal ini, INPC harus diimplementasikan dalam ViewModel.

stéphane Boutinet
sumber
1

Saya menggunakan INotifyPropertyChangeantarmuka dalam model. Sebenarnya, perubahan properti model harus dipecat oleh UI atau klien eksternal saja.

Saya perhatikan beberapa kelebihan dan kekurangan:

Keuntungan

Notifier ada dalam model bisnis

  1. Sesuai domain yang digerakkan, itu benar. Seharusnya memutuskan kapan menaikkan dan kapan tidak.

Kekurangan

Model ini memiliki properti (qty, rate, komisi, totalfrieght). Totalfrieght dihitung menggunakan qty, rate, perubahan komisi.

  1. Pada memuat nilai dari db, perhitungan total frieght disebut 3 kali (qty, rate, komisi). Itu harus sekali.

  2. Jika nilai, qty ditugaskan di lapisan bisnis, lagi-lagi pemberi tahu disebut.

  3. Seharusnya ada opsi untuk menonaktifkan ini, mungkin di kelas dasar. Namun, pengembang bisa lupa melakukan ini.

Anand Kumar
sumber
Karena semua kerugian yang Anda daftarkan, Kami baru saja memutuskan bahwa itu adalah keputusan yang SALAH dalam proyek WPF kami yang relatif besar untuk mengimplementasikan INPC dalam model. Mereka hanya harus berurusan dengan lapisan kegigihan. Semua hal lain seperti validasi, pemberitahuan perubahan, dan properti yang dihitung harus ditangani di ViewModel. Sekarang saya jelas mengerti bahwa mengulang model properti di ViewModel TIDAK selalu merupakan pelanggaran prinsip KERING.
try2fly.b4ucry
1

Saya pikir itu semua tergantung pada use case.

Ketika Anda memiliki model sederhana dengan banyak properti, Anda dapat menerapkannya dengan INPC. Secara sederhana saya maksudkan bahwa model ini terlihat seperti POCO .

Jika model Anda lebih kompleks dan menggunakan domain model interaktif - model referensi model, berlangganan acara model lain - menerapkan model acara sebagai INPC adalah mimpi buruk.

Tempatkan diri Anda pada posisi beberapa entitas model yang harus berkolaborasi dengan beberapa model lainnya. Anda memiliki berbagai acara untuk berlangganan. Semuanya diimplementasikan sebagai INPC. Bayangkan event handler yang Anda miliki. Satu kaskade besar jika-klausa dan / atau beralih klausa.

Masalah lain dengan INPC. Anda harus merancang aplikasi Anda untuk mengandalkan abstraksi, bukan implementasi. Ini biasanya dilakukan dengan menggunakan antarmuka.

Mari kita lihat 2 implementasi berbeda dari abstraksi yang sama:

public class ConnectionStateChangedEventArgs : EventArgs
{
    public bool IsConnected {get;set;}
}

interface IConnectionManagerINPC : INotifyPropertyChanged
{
    string Name {get;}
    int ConnectionsLimit {get;}
    /*

    A few more properties

    */
    bool IsConnected {get;}
}

interface IConnectionManager
{
    string Name {get;}
    int ConnectionsLimit {get;}
    /*

    A few more properties

    */
    event EventHandler<ConnectionStateChangedEventArgs> ConnectionStateChanged;
    bool IsConnected {get;}
}

Sekarang lihat keduanya. Apa yang dikatakan IConnectionManagerINPC kepada Anda? Bahwa beberapa propertinya dapat berubah. Anda tidak tahu yang mana dari mereka. Bahkan desainnya hanya perubahan IsConnected, karena sisanya hanya baca-saja.

Sebaliknya, niat IConnectionManager jelas: "Saya dapat memberi tahu Anda bahwa nilai properti IsConnected saya dapat berubah".

dzendras
sumber
1

Cukup gunakan INotifyPropertyChangedi viewmodel Anda dan bukan di Model,

model biasanya menggunakan IDataErrorInfountuk menangani kesalahan validasi jadi tetap di ViewModel Anda dan Anda benar di jalan MVVM Anda.

Adam
sumber
1
Bagaimana dengan model dengan beberapa properti? Anda mengulangi kode dalam VM.
Luis
0

Misalkan referensi objek dalam tampilan Anda berubah. Bagaimana Anda akan memberi tahu semua properti agar diperbarui untuk menunjukkan nilai yang benar? Memanggil OnPropertyChangeddalam pandangan Anda untuk semua properti objek adalah sampah bagi sudut pandang saya.

Jadi yang saya lakukan adalah membiarkan objek itu sendiri untuk memberi tahu siapa pun ketika nilai dalam properti berubah, dan dalam pandangan saya, saya menggunakan binding seperti Object.Property1, Object.Property2dan seterusnya . Dengan cara itu jika saya hanya ingin mengubah objek yang saat ini dipertahankan dalam pandangan saya, saya hanya melakukannya OnPropertyChanged("Object").

Untuk menghindari ratusan pemberitahuan selama pemuatan objek, saya memiliki indikator boolean pribadi yang saya atur menjadi true selama pemuatan yang diperiksa dari objek OnPropertyChangeddan tidak melakukan apa pun.

Dummy01
sumber
0

Biasanya ViewModel akan mengimplementasikan INotifyPropertyChanged. Model dapat berupa apa saja (file xml, basis data atau bahkan objek). Model digunakan untuk memberikan data ke viewmodel, yang menyebar ke tampilan.

Lihat disini

Syed
sumber
1
emm .. tidak. Model tidak boleh berupa file atau basis data xml. Dan model tidak digunakan untuk memberikan data. Kalau tidak, seharusnya tidak disebut "model" tetapi "data" ..? Model digunakan untuk menggambarkan data. Cukup jelas, bukan? :)
Taras
1
Jika Anda memiliki jawaban yang lebih baik, silakan bagikan! kita semua di sini untuk berbagi pengetahuan dan bukan untuk bersaing
Adam
0

imho saya pikir mengimplementasikan INotifyPropertyChangemodel viewmodel dan dapat menggunakan notifikasi pada "level" yang berbeda.

mis. dengan beberapa layanan dokumen dan objek dokumen Anda memiliki acara DocumentChanged yang viewmodel mendengarkan untuk menghapus dan membangun kembali view. Dalam model tampilan edit Anda memiliki pertukaran properti untuk properti dokumen untuk mendukung tampilan. Jika layanan ini sangat membantu dengan menyimpan dokumen (memperbarui tanggal perubahan, pengguna terakhir, dan sebagainya), Anda dengan mudah mendapatkan kelebihan acara Ipropertychanged dan hanya perubahan dokumen saja sudah cukup.

Tetapi jika Anda menggunakan INotifyPropertyChangedalam model Anda, saya pikir itu adalah praktik yang baik untuk menyampaikannya di viewmodel Anda sebagai ganti berlangganan secara langsung dalam pandangan Anda. Dalam hal ini ketika peristiwa berubah dalam model Anda, Anda hanya perlu mengubah model tampilan dan tampilan tetap tidak tersentuh.

Bram
sumber
0

Semua properti, yang terikat pada pandangan saya, ada di dalam ViewModel saya. Jadi mereka harus mengimplementasikan antarmuka INotifyPropertyChanged. Oleh karena itu, View mendapatkan semua perubahan.

[Menggunakan toolkit MVVM Light, saya membiarkan mereka mewarisi dari ViewModelBase.]

Model memegang logika bisnis, tetapi tidak ada hubungannya dengan pandangan. Jadi tidak perlu untuk antarmuka INotifyPropertyChanged.

jangan membuat kesalahan
sumber