MVVM'de ViewModel veya Model INotifyPropertyChanged uygulamalıdır mı?


165

Üzerinde çalıştığım çoğu MVVM örneğinde Model uygulaması vardı INotifyPropertyChanged, ancak Josh Smith'in CommandSink örneğinde ViewModel uygulandıINotifyPropertyChanged .

Hala bilişsel olarak MVVM kavramlarını bir araya getiriyorum, bu yüzden bilmiyorum:

  • Çalışmak INotifyPropertyChangediçin ViewModel'e koymanız gerekirCommandSink
  • Bu sadece normların bir sapması ve gerçekten önemli değil
  • Her zaman Model uygulamasını kullanmalısınız INotifyPropertyChangedve bu sadece bir kod örneğinden bir uygulamaya geliştirildiyse düzeltilecek bir hatadır

Başkalarının üzerinde çalıştığınız MVVM projeleriyle ilgili deneyimleri nelerdi?


4
INPC uygularsanız, github.com/Fody/PropertyChanged komutunu deneyin - yazmanızdan haftalarca tasarruf etmenizi sağlar.
CAD bloke

Yanıtlar:


104

Tam tersini söyleyebilirim, her zaman INotifyPropertyChangedViewModel'imi taktım - modelinizi oldukça WPF'ye özgü bir özellikle kirletmek istemiyorsunuz INotifyPropertyChanged, bu şeyler ViewModel'de oturmalıdır.

Eminim başkaları aynı fikirde değil, ama ben böyle çalışıyorum.


84
Modelde bir özellik değişirse ne yaparsınız? Bir şekilde görünüm modeline götürmeniz gerekiyor. Dürüst soru, şu anda bu muamma ile ilgileniyorum.
Roger Lipscombe

4
Prism kodundaki EventAggregator, özel özellik değiştirilmiş olay türüyle modelde INotifyPropertyChanged'e iyi bir alternatiftir. Bu projedeki olay kodu, bazen sorun olabilecek arka plan ve kullanıcı arayüzü iş parçacıkları arasında olay iletmeyi destekler.
Steve Mitcham

51
INotifyProperyChanged WPF'ye özgü değildir, System.ComponentModel ad alanında yaşıyor, WinForms uygulamalarında kullandım, ayrıca INotifyPropertyChanged
.Net'ten

40
Ben hem MODEL hem de VIEWMODEL INotifyPropertyChanged koyarak hayranıyım. Bunu yapmamak için bir neden düşünemiyorum. Bu, VIEWMODEL'i, VIEWMODEL'i etkileyen ve VIEWMODEL'i etkileyen ve VIEWMODEL'de değişiklikler olduğu gibi MOD'unuzda arka plan değişikliklerinin ne zaman gerçekleştiğini bildirmenin zarif bir yoludur.
ScottCher

6
@Steve - ViewModel'e bir Modelin özelliğinin değiştiğini bildirme hakkında, INotifyPropertyChanged "viewmodel'in bağlanabileceği bir olay" gibi iyi çalışıyor gibi görünüyor. Neden kullanmıyorsunuz?
skybluecodeflier

146

Modelin uygulamaması gerektiği fikrine kesinlikle katılmıyorum INotifyPropertyChanged. Bu arayüz kullanıcı arayüzüne özgü değil! Sadece bir değişiklik hakkında bilgi verir. Gerçekten de, WPF bunu değişiklikleri tanımlamak için yoğun bir şekilde kullanır, ancak bu bir UI arayüzü olduğu anlamına gelmez. Ben şu yorum ile karşılaştırmak istiyorum: " Bir lastik bir araba aksesuarıdır ". Elbette öyle, ama bisiklet, otobüs vb. De kullanıyor. Özetle, bu arayüzü bir kullanıcı arayüzü olarak kabul etmeyin.

Bunu söyledikten sonra, Modelin bildirimler sunması gerektiğine inanmam anlamına gelmez. Aslında, bir kural olarak, model gerekli olmadığı sürece bu arayüzü uygulamamalıdır. İstemci uygulamasına hiçbir sunucu verisi aktarılmadığında çoğu durumda model eski olabilir. Ancak finansal piyasa verilerini dinliyorsam, modelin neden arayüzü uygulayamadığını göremiyorum. Örnek olarak, belirli bir değer için bir Teklif veya Sor fiyatı aldığında bir uyarı (ör. E-posta yoluyla) veren veya sipariş veren bir hizmet gibi UI olmayan mantığım varsa ne olur? Bu olası temiz bir çözüm olabilir.

Bununla birlikte, bir şeyleri başarmanın farklı yolları vardır, ancak her zaman basitlik lehinde tartışır ve fazlalıktan kaçınırım.

Ne daha iyi? Bir koleksiyondaki veya mülkteki olayları tanımlama görünüm modelinde değişir ve modele yayılır mı veya görünümün modeli kendiliğinden güncellemesi mi (görünüm modeli aracılığıyla)?

Sonuç olarak, " Bunu yapamazsın ya da yapamazsın " diye iddia eden birini gördüğünde , neden bahsettiklerini bilmediklerinin bir işaretidir.

Bu gerçekten sizin durumunuza bağlıdır ve aslında MVVM birçok sorun içeren bir çerçevedir ve henüz MVVM'nin genel bir uygulamasını görmüyorum.

Keşke MVVM'nin birçok çeşidini ve çoğunlukla diğer geliştiriciler tarafından sağlanan ortak sorunlara bazı çözümleri açıklamak için daha fazla zamanım olsaydı, ama sanırım bunu başka bir zaman yapmak zorunda kalacağım.


7
Bu şekilde düşün. Bir geliştirici olarak Modeller ile bir .dll tüketirseniz, kesinlikle INotifyPropertyChanged desteklemek için bunları yeniden yazmak olmaz.
Lee Treveil

2
Kesinlikle sana katılıyorum. Benim gibi, resmi MVVM belgelerinin < msdn.microsoft.com/en-us/library/gg405484%28v=pandp.40%29.aspx > (Model bölümü) 'nin bizimle aynı fikirde olduğunu da öğrenebilirsiniz . :-)
Noldorin

"Bununla birlikte, şeylere ulaşmanın farklı yolları vardır, ancak her zaman basitlik lehine tartışır ve işten çıkarılmayı önlerim." Çok önemli.
Bastien Vandamme

1
INotifyPropertyChangedSystem.ComponentModel" Bileşenlerin ve denetimlerin çalışma zamanı ve tasarım zamanı davranışı " için kullanılan ad alanının bir parçasıdır . Modellerde, sadece ViewModels'de KULLANMAYIN INotifyPropertyChanged . Dokümanlara bağlantı: docs.microsoft.com/en-us/dotnet/api/system.componentmodel
Igor Popov

1
Eski yazı, biliyorum, ama MVVM kullanarak yeni bir projeye başlarken sık sık geri dönüyorum. Son zamanlarda Tek Sorumluluk İlkesini çok daha sıkı bir şekilde uygulamaya başladım. Bir modelin bir sorumluluğu vardır. Model olmak. Modele INotifyPropertyChanged'i eklediğinizde, artık Tek Sorumluluk İlkesi'ne uymuyor. ViewModel'in var olmasının tüm nedeni, modelin model olmasına izin vermek, modelin tek bir sorumluluğa sahip olmasını sağlamaktır.
Rhyous


13

Ben MVVM çok kötü adlandırılmış ve ViewModel bir ViewModel çağırmak çok iyi tasarlanmış bir mimarinin önemli bir özelliği kaçırmak neden olur, hangi veri dokunmaya çalışıyor olursa olsun verileri kontrol bir DataController olduğunu.

View-Model'i daha fazla DataController olarak görüyorsanız ve DataController'ınızın verilere dokunan tek öğe olduğu bir mimari uygularsanız, asla verilere doğrudan dokunmazsınız, ancak her zaman DataController'ı kullanırsınız. DataController UI için yararlıdır, ancak yalnızca UI için gerekli değildir. İş katmanı, UI katmanı vb.Için ...

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

Sonunda böyle bir model elde edersiniz. İşletme bile verilere yalnızca ViewModel kullanarak dokunmalıdır. Sonra bilmeceniz kaybolur.


3
Verileriniz yalnızca DataController değiştirdiğinde değişirse harika olur. Veriler bir veritabanından veya değişiklik için başka bir yol sağlayabilen başka bir veri deposundan geliyorsa, VIEWMODEL'i (deseninizdeki DataController) ve VIEW'ı bilgilendirmek için bir yolunuz olması gerekebilir. DataController'ı kullanarak yoklayabilir veya harici bir işlemden DataModel'inize aktarabilir ve DataModel'inizin DataController'ınıza değişiklik bildirimleri göndermesine izin verebilirsiniz.
ScottCher

4
Kesinlikle haklısın. Tasarım kalıpları çok üst seviyededir. Çoğu zaman tasarım deseni sizi doğru şeyleri yapmaya yönlendirir, ancak her seferinde sizi yanlış yöne çevirirler. Bir şeyleri doğru yapmaktan asla kaçınmamalısınız, çünkü tasarım deseninizin dışında.
Rhyous

Ayrıca, DataController'ınızı kontrol ederken ve veri modelinde zorlarsınız ve güncellemesini söylerdiniz.
Rhyous

Ayrıca, MVVM'deki Model, kullanıcı arayüzü (ör. DTO) için gerektiği şekilde spesifik tutulmalıdır. Bu nedenle, herhangi bir DB veya karmaşık iş mantığı farklı bir katmanda gerçekleşmeli ve daha sonra görünüm modeli aracılığıyla ham bir veri sağlanmalıdır.
Kod Adı Jack

9

Modelinizi nasıl uyguladığınıza bağlıdır. Şirketim, Lhotka'nın CSLA nesnelerine benzer iş nesneleri kullanıyor INotifyPropertyChangedve iş modelinin tamamından faydalanıyor .

Doğrulama motorumuz ağırlıklı olarak özelliklerin bu mekanizma yoluyla değiştiği konusunda bilgilendirilmeye dayanır ve çok iyi çalışır. Açıkçası, değişiklik bildirimlerinin işlem için kritik olmadığı iş nesneleri dışında farklı bir uygulama kullanıyorsanız, iş modelinizdeki değişikliği tespit etmek için başka yöntemleriniz olabilir.

Modeldeki değişiklikleri gereken yerlerde yayan Görünüm Modellerimiz de var, ancak Görünüm Modellerinin kendisi temel Model değişikliklerini dinliyor.


3
Model'in OnPropertyChanged'ini ViewModel'in OnPropertyChanged'e tam olarak nasıl yayıyorsunuz? ViewModel, Model'den farklı özellik adlarına sahip olduğunda bir sorunum var - bir tür ad-ad eşlemesi gerekli olacaktı, değil mi?
Martin Konicek

Gerçekten sofistike bir şey değil, sadece olayları iletiyoruz. Sanırım isimler farklıysa bir arama tablosu kullanılabilirdi. Değişiklik bire bir eşleme olmasaydı, o zaman olayı bağlayabilir ve daha sonra işleyicide gerekli olayları tetikleyebilirsiniz.
Steve Mitcham

6

Paulo'nun cevabına katılıyorum INotifyPropertyChanged, Modellerde uygulamak tamamen kabul edilebilir ve hatta Microsoft tarafından öneriliyor -

Tipik olarak, model görünüme bağlanmayı kolaylaştıran tesisleri uygular. Bu genellikle INotifyPropertyChangedve INotifyCollectionChangedarabirimleri aracılığıyla özellik ve koleksiyon değiştirilmiş bildirimi desteklediği anlamına gelir . Nesnelerin koleksiyonlarını temsil eden modeller sınıfları, genellikle arabirimin ObservableCollection<T>bir uygulamasını sağlayan sınıftan türetilir INotifyCollectionChanged.

Her ne kadar bu tür bir uygulama isteyip istemediğinize karar vermek size kalmış, ancak unutmayın -

Model sınıflarınız gerekli arabirimleri uygulamazsa ne olur?

Bazen uygulamak gerekmez modeli nesnelerle çalışması gerekecek INotifyPropertyChanged, INotifyCollectionChanged, IDataErrorInfo, veya INotifyDataErrorInfoarayüzleri. Bu durumlarda, görünüm modelinin model nesnelerini sarması ve gerekli özellikleri görünüme göstermesi gerekebilir. Bu özelliklerin değerleri doğrudan model nesneleri tarafından sağlanacaktır. Görünüm modeli, görünümün onlara kolayca veri bağlayabilmesi için gösterdiği özellikler için gerekli arabirimleri uygulayacaktır.

Alınan - http://msdn.microsoft.com/en-us/library/gg405484(PandP.40).aspx

INotifyPropertyChangedModellerimizde uygulamadığımız bazı projelerde çalıştım ve bu nedenle birçok sorunla karşı karşıya kaldık; VM'de özelliklerin gereksiz bir şekilde kopyalanması gerekiyordu ve aynı zamanda temel nesneyi (güncellenmiş değerlerle) BL / DL'ye geçirmeden önce güncellememiz gerekiyordu.

Model nesnelerinizin (örneğin düzenlenebilir bir ızgarada veya listede) veya karmaşık modellerin toplanmasıyla çalışmanız gerektiğinde özel olarak sorunlarla karşılaşacaksınız; model nesneler otomatik olarak güncellenmez ve sanal makinenizdeki her şeyi yönetmeniz gerekir.


3

Ancak bazen (bu sunum bağlantı metninde olduğu gibi ) modeli, çevrimiçi olarak bazı verilerle uygulama sağlayan hizmettir ve daha sonra yeni verilerin geldiğini veya verilerin olayları kullanarak değiştiğini bildirmeniz gerekir ...


3

MV-VM'ye bağlı kalmak istiyorsanız cevabın oldukça açık olduğunu düşünüyorum.

bkz. http://msdn.microsoft.com/tr-tr/library/gg405484(v=PandP.40).aspx

MVVM modelinde, görünüm kullanıcı arabirimini ve herhangi bir kullanıcı arabirimi mantığını, görünüm modeli sunum mantığını ve durumunu ve model iş mantığı ve verilerini kapsar.

"Görünüm, veri bağlama, komutlar ve değişiklik bildirim olayları aracılığıyla görünüm modeliyle etkileşime girer. Görünüm modeli, görünümdeki görüntüleme için gereken verileri dönüştürmek, doğrulamak ve toplamak için modeldeki güncellemeleri sorgular, gözlemler ve koordine eder."


4
Alıntı yoruma açıktır. Sanırım cevabınızı netleştirmek için yorumunuzu eklemelisiniz :-)
Søren Boisen

@John D: Bu makale sadece bir MVVM yorumu ve onu uygulamanın bir yolunu veriyor, MVVM'yi tanımlamıyor.
akjoshi

Ayrıca, makalenin tamamını okursanız Model sınıfını şu şekilde tanımlar: "Tipik olarak, model görünüme bağlanmayı kolaylaştıran tesisler uygular. Nesne koleksiyonlarını temsil eden modeller, tipik olarak INotifyCollectionChanged arabiriminin bir uygulamasını sağlayan ObservableCollection <T> sınıfından türetilir. "
akjoshi

2

ViewModel'inizde söyleyebilirim. Model UI agnostik olduğundan Modelin bir parçası değildir. Model 'ticari agnostik hariç her şey' olmalıdır


2

Modeller ViewModel'de açıkça gösteriliyorsa modellerde INPC uygulamak kullanılabilir. Ancak genellikle, ViewModel modelleri sarın, model karmaşıklığını azaltmak için kendi sınıflarıdır (bu, bağlanma için yararlı olmamalıdır). Bu durumda, INPC'nin ViewModel uygulamasında uygulanması gerekir.


1

Ben kullanıyorum INotifyPropertyChangebir modelde arayüz. Aslında, model özellik değişikliği yalnızca kullanıcı arayüzü veya harici istemci tarafından başlatılmalıdır.

Birkaç avantaj ve dezavantaj fark ettim:

Avantajları

Bildirimci iş modelindedir

  1. Etki alanına göre, doğru. Ne zaman ve ne zaman kalkmayacağına karar vermelidir.

Dezavantajları

Modelin özellikleri vardır (adet, oran, komisyon, toplam frekans). Toplam uzunluk, miktar, oran, komisyon değişikliği kullanılarak hesaplanır.

  1. Db'den yüklenen değerlerde toplam frieght hesaplaması 3 kez denir (adet, oran, komisyon). Bir kez olmalı.

  2. Oran, iş katmanında adet atanırsa, tekrar bildirim çağrılır.

  3. Muhtemelen temel sınıfta bunu devre dışı bırakma seçeneği olmalıdır. Ancak, geliştiriciler bunu yapmayı unutabilirler.


Listelediğiniz tüm dezavantajlar nedeniyle, nispeten büyük WPF projemizde INPC'yi modellerde uygulamanın WRONG kararı olduğuna karar verdik. Sadece kalıcılık katmanıyla ilgilenmelidirler. Doğrulama, değişiklik bildirimi ve hesaplanan özellikler gibi tüm diğer şeyler ViewModel'de işlenmelidir. Şimdi ViewModel'de tekrarlanan model özelliklerinin her zaman KURU prensibinin ihlali olmadığını açıkça anlıyorum.
try2fly.b4ucry

1

Her şeyin kullanım durumuna bağlı olduğunu düşünüyorum.

Çok sayıda özelliğe sahip basit bir modeliniz olduğunda, INPC'yi uygulamasını sağlayabilirsiniz. Basitçe söylemek gerekirse, bu model bir POCO'ya benziyor .

Modeliniz daha karmaşıksa ve etkileşimli bir model etki alanında yaşıyorsa - modelleri referans alan modeller, diğer modellerin etkinliklerine abone olma - model etkinliklerin INPC olarak uygulanması bir kabustur.

Kendinizi diğer bazı modellerle birlikte çalışması gereken bir model varlığın konumuna getirin. Abone olmak için çeşitli etkinlikleriniz var. Hepsi INPC olarak uygulanır. Sahip olduğunuz olay işleyicilerini hayal edin. Büyük bir if-yan tümcesi ve / veya anahtar yan tümcesi.

INPC ile ilgili başka bir sorun. Uygulamalarınızı uygulamaya değil, soyutlamaya dayanacak şekilde tasarlamalısınız. Bu genellikle arabirimler kullanılarak yapılır.

Aynı soyutlamanın 2 farklı uygulamasına bakalım:

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;}
}

Şimdi ikisine de bakın. IConnectionManagerINPC size ne anlatıyor? Bazı özellikleri değişebilir. Hangisini bilmiyorsun. Aslında tasarım, sadece IsConnected değişikliklerinin geri kalanı salt okunur olduğu için.

Diğer taraftan, IConnectionManager'ın niyetleri açıktır: "Size IsConnected özelliğimin değerinin değişebileceğini söyleyebilirim".


1

Sadece INotifyPropertyChange Model içinden ViewModel değil,

model genellikle IDataErrorInfodoğrulama hatalarını işlemek için kullanır, bu nedenle yalnızca ViewModel'inizde tutun ve MVVM yolundasınız.


1
Çeşitli özelliklere sahip modeller ne olacak? VM'de kodu tekrarlıyorsunuz.
Luis

0

Görünümünüzdeki nesnenin referansının değiştiğini varsayalım. Doğru değerleri göstermek için tüm mülklerin güncellenmesini nasıl bildireceksiniz? OnPropertyChangedTüm nesnenin özellikleri için görüşünüzü çağırmak benim bakış açımdan saçma.

Yani yaptığım şey, bir özellikteki bir değer değiştiğinde nesnenin kendisini kimseye bildirmesine izin vermek ve benim görüşüme göre Object.Property1, Object.Property2ve gibi bağlamaları kullanıyorum . Bu şekilde sadece şu anda benim görüşüme göre korunan nesneyi değiştirmek istiyorsanız sadece yaparım OnPropertyChanged("Object").

Nesnelerin yüklenmesi sırasında yüzlerce bildirimden kaçınmak için, nesnenin kontrol edilir OnPropertyChangedve hiçbir şey yapmazken yükleme sırasında true olarak ayarladığım özel bir boole göstergesim var .


0

Normalde ViewModel INotifyPropertyChanged. Model herhangi bir şey olabilir (xml dosyası, veritabanı veya hatta nesne). Model, verileri görünüme yansıtan görünüm modeline vermek için kullanılır.

buraya bakın


1
emm .. hayır. Model xml dosyası veya veritabanı olamaz. Ve model veri vermek için kullanılmaz. Aksi takdirde "model" değil "veri" olarak adlandırılmalıdır. Verileri tanımlamak için model kullanılır. Kendini açıklayan oldukça değil mi? :)
Taras

1
Daha iyi bir cevabınız varsa, lütfen paylaşın! hepimiz bilgiyi paylaşmak ve rekabet etmemek için buradayız
Adam

0

imho ben viewmodel uygular INotifyPropertyChangeve model farklı bir "düzeyde" bildirim kullanabilirsiniz düşünüyorum .

örneğin, bazı belge servisi ve belge nesnesiyle, bir görünüm modelinin görünümü temizlemek ve yeniden oluşturmak için dinlediği bir documentChanged etkinliğiniz vardır. Düzenleme görünüm modelinde, görünümleri destekleyen belgenin özellikleri için bir özellik değişiminiz vardır. Hizmet, kaydetme belgesinde (değişiklik tarihini, son kullanıcı vb.) Çok şey yaparsa, Ipropertychanged olaylarının aşırı yüklenmesini kolayca elde edersiniz ve sadece bir belge değişimi yeterlidir.

Ancak INotifyPropertyChangemodelinizde kullanırsanız , doğrudan görüşünüze abone olmak yerine onu görünüm modelinizde aktarmanın iyi bir uygulama olduğunu düşünüyorum. Bu durumda, modelinizdeki olaylar değiştiğinde yalnızca görünüm modelini değiştirmeniz gerekir ve görünüm dokunulmadan kalır.


0

Görünümüme bağlanan tüm özellikler, ViewModel (ler )imde. Bu nedenle INotifyPropertyChanged arabirimini uygulamalıdırlar. Bu nedenle, Görünüm tüm değişiklikleri alır.

[MVVM Light araç setini kullanarak onları ViewModelBase'den devralmalarına izin verdim.]

Model, iş mantığına sahiptir, ancak görünümle hiçbir ilgisi yoktur. Böylece INotifyPropertyChanged arabirimine gerek kalmaz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.