MVVM Şablonunun iyi örnekleri


141

Şu anda Microsoft MVVM şablonu ile çalışıyorum ve sinir bozucu ayrıntılı örneklerin eksikliği bulmak. Dahil edilen ContactBook örneği çok az Komut işleme gösterir ve bulduğum diğer tek örnek, kavramların benzer olduğu ancak biraz farklı bir yaklaşım kullandığı ve hala herhangi bir karmaşıklık bulunmadığı bir MSDN Magazine makalesinden alınmıştır. En azından temel CRUD işlemlerini ve iletişim kutusu / içerik geçişini gösteren iyi MVVM örnekleri var mı?


Herkesin önerileri gerçekten faydalıydı ve iyi kaynakların bir listesini derlemeye başlayacağım

Çerçeveler / Şablonlar

Yararlı Makaleler

Screencasts

Ek Kütüphaneler


Bu kaynakların yardımcı olduğu için mutluyum. Şu anda ikinci üretim MVVM uygulamamdayım ve karşılaştığımda başlayanlara yardımcı olacak içerik eklemeye devam edeceğim.
jwarzech

Yanıtlar:


59

Ne yazık ki, her şeyi yapan harika bir MVVM örnek uygulaması yok ve bir şeyler yapmak için birçok farklı yaklaşım var. İlk olarak, size uygun farklı desenleri kolayca denemek için size bağımlılık enjeksiyonu, komuta, olay toplama, vb.Gibi kullanışlı araçlar sağladığından, uygulama çerçevelerinden birini tanımak isteyebilirsiniz (Prizma iyi bir seçimdir). .

Prizma sürümü:
http://www.codeplex.com/CompositeWPF

Bir sürü küçük örnek ve nasıl yapılır ile birlikte oldukça iyi bir örnek uygulama (borsa tüccar) içerir. En azından insanların MVVM'nin gerçekten çalışması için kullandıkları birkaç ortak alt modelin iyi bir gösterimi. Hem CRUD hem de diyaloglar için örnekleri var.

Prizma her proje için mutlaka gerekli değildir, ancak aşina olmak iyi bir şeydir.

CRUD: Bu bölüm oldukça kolay, WPF iki yönlü bağlamalar çoğu verinin düzenlenmesini gerçekten kolaylaştırıyor. Gerçek hile UI kurulumunu kolaylaştıran bir model sağlamaktır. En azından ViewModel (veya iş nesnesi) INotifyPropertyChangedbağlamayı desteklemek için uygulandığından emin olmak istersiniz ve özellikleri doğrudan UI denetimlerine bağlayabilirsiniz, ancak IDataErrorInfodoğrulama için de uygulamak isteyebilirsiniz . Genellikle, bir çeşit ORM çözümü kullanırsanız CRUD kurmak çok kolaydır.

Bu makalede, basit crud işlemleri gösterilmektedir: http://dotnetslackers.com/articles/wpf/WPFDataBindingWithLINQ.aspx

LinqToSql üzerine inşa edilmiştir, ancak bu örnekle ilgisizdir - önemli olan iş nesnelerinizin INotifyPropertyChanged(LinqToSql tarafından oluşturulan sınıfların yaptığı) uygulanmasıdır. MVVM bu örneğin amacı değil, ama bu durumda önemli olduğunu düşünmüyorum.

Bu makalede veri doğrulaması gösterilmektedir
http://blogs.msdn.com/wpfsdk/archive/2007/10/02/data-validation-in-3-5.aspx

Yine, çoğu ORM çözümü zaten uygulanmış IDataErrorInfove tipik olarak özel doğrulama kuralları eklemeyi kolaylaştıran bir mekanizma sağlayan sınıflar oluşturur .

Çoğu zaman bir ORM tarafından oluşturulan bir nesneyi (modeli) alabilir ve onu tutan ve kaydet / sil komutlarını içeren bir ViewModel'e sarabilirsiniz ve kullanıcı arayüzünü doğrudan modelin özelliklerine bağlamaya hazırsınız.

Görünüm şöyle görünecektir (ViewModel, ORM'de Itemoluşturulan bir sınıf gibi modeli tutan bir özelliğe sahiptir):

<StackPanel>
   <StackPanel DataContext=Item>
      <TextBox Text="{Binding FirstName, Mode=TwoWay, ValidatesOnDataErrors=True}" />
      <TextBox Text="{Binding LastName, Mode=TwoWay, ValidatesOnDataErrors=True}" />
   </StackPanel>
   <Button Command="{Binding SaveCommand}" />
   <Button Command="{Binding CancelCommand}" />
</StackPanel>

Diyaloglar: Diyaloglar ve MVVM biraz zor. İletişim kutuları ile arabulucu yaklaşımının bir lezzetini kullanmayı tercih ederim, bu StackOverflow sorusunda biraz daha okuyabilirsiniz:
WPF MVVM iletişim örneği

Oldukça klasik MVVM olmayan her zamanki yaklaşımım şöyle özetlenebilir:

Tamamlama ve iptal eylemleri için komutları gösteren bir iletişim kutusu ViewModel için temel sınıf, görünümün bir iletişim kutusunun kapatılmaya hazır olduğunu bilmesini sağlayan bir olay ve tüm iletişim kutularında ihtiyacınız olan her şey.

Diyalog pencereniz için genel bir görünüm - bu bir pencere veya özel bir "kalıcı" kaplama türü kontrolü olabilir. Kalbinde, viewmodel'i içine döktüğümüz bir içerik sunucusu ve pencereyi kapatmak için kabloları kullanıyor - örneğin veri bağlamında yeni ViewModel'in temel sınıfınızdan miras alınıp alınmadığını kontrol edebilir ve ilgili kapatma etkinliğine abone olun (işleyici iletişim kutusu sonucunu atar). Alternatif evrensel kapatma işlevselliği sağlarsanız (örneğin X düğmesi), ViewModel'de de ilgili kapatma komutunu çalıştırdığınızdan emin olmalısınız.

ViewModels'ınız için veri şablonları sağlamanız gereken bir yerde, özellikle ayrı bir kontrolde kapsüllenmiş her iletişim kutusu için bir görünümünüz olduğundan, bunlar çok basit olabilir. ViewModel için varsayılan veri şablonu aşağıdaki gibi görünecektir:

<DataTemplate DataType="{x:Type vmodels:AddressEditViewModel}">
   <views:AddressEditView DataContext="{Binding}" />
</DataTemplate>

İletişim kutusu görünümünün bunlara erişimi olması gerekir, aksi takdirde paylaşılan iletişim arabirimi arayüzünün içeriği temel olarak şudur: Aksi takdirde ViewModel'in nasıl gösterileceğini bilemez:

<ContentControl Content="{Binding}" />

Örtük veri şablonu, görünümü modele eşler, ancak bunu kim başlatır?

Bu öyle değil mvvm kısmı. Bunu yapmanın bir yolu küresel bir olay kullanmaktır. Ne yapmak daha iyi bir şey olduğunu düşünüyorum bağımlılık enjeksiyon yoluyla sağlanan bir olay toplayıcı türü kurulum kullanmaktır - bu şekilde olay tüm uygulama değil, bir kapsayıcı için küreseldir. Prizma kap semantiği ve bağımlılık enjeksiyonu için birlik çerçevesini kullanır ve genel olarak Unity'yi biraz severim.

Genellikle, kök pencerenin bu olaya abone olması mantıklıdır - iletişim kutusunu açabilir ve veri içeriğini yükseltilmiş bir olayla aktarılan ViewModel'e ayarlayabilir.

Bunu bu şekilde ayarlamak, ViewModels'ın uygulamadan kullanıcı arabirimi hakkında hiçbir şey bilmeden bir iletişim kutusu açmasını ve kullanıcı işlemlerine yanıt vermesini ister, böylece çoğunlukla MVVM-ness tamamlanır.

Bununla birlikte, kullanıcı arayüzünün diyalogları yükseltmesi gereken zamanlar vardır, bu da işleri biraz daha zorlaştırabilir. Örneğin, iletişim kutusu konumu onu açan düğmenin konumuna bağlıysa düşünün. Bu durumda, bir iletişim kutusu açılmasını istediğinizde kullanıcı arayüzüne özgü bazı bilgilere sahip olmanız gerekir. Genelde bir ViewModel ve bazı ilgili UI bilgilerini tutan ayrı bir sınıf oluştururum. Ne yazık ki, bazı kaplin kaçınılmaz gibi görünüyor.

Öğe konum verisi gerektiren bir iletişim kutusunu yükselten bir düğme işleyicinin sözde kodu:

ButtonClickHandler(sender, args){
    var vm = DataContext as ISomeDialogProvider; // check for null
    var ui_vm = new ViewModelContainer();
    // assign margin, width, or anything else that your custom dialog might require
    ...
    ui_vm.ViewModel = vm.SomeDialogViewModel; // or .GetSomeDialogViewModel()
    // raise the dialog show event
}

İletişim kutusu görünümü konum verilerine bağlanır ve içerilen ViewModel'i içe aktarır ContentControl. ViewModel'in kendisi hala kullanıcı arayüzü hakkında hiçbir şey bilmiyor.

Genelde yöntemin DialogResultreturn özelliğini kullanmıyorum ShowDialog()veya iletişim kutusu kapatılana kadar iş parçacığının engellenmesini beklemiyorum. Standart olmayan bir mod iletişim kutusu her zaman böyle çalışmaz ve kompozit bir ortamda bir olay işleyicinin böyle bir şekilde engellemesini istemezsiniz. ViewModels'ın bununla başa çıkmasına izin vermeyi tercih ediyorum - bir ViewModel'in yaratıcısı ilgili etkinliklerine abone olabilir, taahhüt / iptal yöntemlerini ayarlayabilir vb. Bu yüzden bu kullanıcı arayüzü mekanizmasına güvenmeye gerek yoktur.

Bu akış yerine:

// in code behind
var result = somedialog.ShowDialog();
if (result == ...

Kullanırım:

// in view model
var vm = new SomeDialogViewModel(); // child view model
vm.CommitAction = delegate { this.DoSomething(vm); } // what happens on commit 
vm.CancelAction = delegate { this.DoNothing(vm); } // what happens on cancel/close (optional)
// raise dialog request event on the container

Bu şekilde tercih ediyorum çünkü diyaloglarımın çoğu engellemeyen sahte mod kontrolleri ve bu şekilde yapmak, etrafta çalışmaktan daha basit görünüyor. Birim testi de kolaydır.


Ayrıntılı cevap için teşekkürler! Geçenlerde en büyük sorunum, uygulamanın akışını işlemek için diğer görünüm modelleri ile iletişim kurmak için bir MainViewModel gerektiğinde bulundu. Bununla birlikte, MVVM + Arabulucunun popüler yaklaşım olduğu görülmektedir.
jwarzech

2
Arabulucu kesinlikle yardımcı olur, düşük toplayıcı bir hedef olduğunda olay toplayıcı modeli (Prism iyi bir uygulamaya sahiptir) de gerçekten yararlıdır. Ayrıca, ana görünüm modelinizde genellikle kendi alt görünüm modelleri vardır ve onlarla iletişimde sorun yaşamamalıdır. Alt görünüm modellerinizin uygulamanızdaki kullanıcı arayüzü dahil olmak üzere bilmedikleri diğer modüllerle etkileşim kurması gerektiğinde bir arabulucu veya / ve etkinlik toplayıcı kullanmanız gerekir (iletişim kutusu örneğim bu özel durumla ilgilidir).
Egor

1
İletişim kutuları ve pencerelerle çalışma yönergeleri gerçekten yardımcı oldu. Ancak, birkaç sorunla karşı karşıya kaldım: 1. Pencere başlığını görünümden nasıl ayarlarsınız? 2. Sahip penceresini ayarlamakla nasıl başa çıkıyorsunuz?
djskinner

@Daniel Skinner: Burada diyaloglar hakkında konuştuğunuzu varsayıyorum, yanılıyorsam beni düzeltin. İletişim kutusu başlığı yalnızca başka bir özelliktir ve istediğiniz her şeye bağlayabilirsiniz. Temel iletişim kutusu viewmodel sınıfıyla yaklaşımımı izlediyseniz (bir başlık özelliğine sahip olduğunu varsayalım), genel jenerik iletişim pencerenizde başlığı {Binding Path = DataContext.Title, ElementName = NameOfContentPresenter}. Sahip penceresi biraz hiledir - aslında iletişim kutusunu açan aracının kök uygulama görünümü hakkında bilgi sahibi olması gerektiği anlamına gelir.
Egor

Aslında bunu geri alıyorum - bunu bir noktada nasıl yapılandırdığınıza bakılmaksızın, iletişim kutusunu kimin açtığına bakılmaksızın, kök uygulama penceresine / görünümüne bir referans olması gerekir. "Genellikle, kök pencerenin bu olaya abone olması mantıklıdır - iletişim kutusunu açabilir ve veri içeriğini yükseltilmiş bir etkinlikle geçirilen görünüm modeline ayarlayabilir." Bu, sahibi ayarlayacağınız yerdir.
Egor

6

Jason Dolinger MVVM'den iyi bir ekran görüntüsü aldı . Egor'un belirttiği gibi, iyi bir örnek yok. Hepsi bitti. Çoğu iyi MVVM örnekleridir, ancak karmaşık sorunlara girdiğinizde değil. Herkesin kendi yolu var. Laurent Bugnion, görünüm modelleri arasında iletişim kurmanın iyi bir yoluna sahiptir. http://blog.galasoft.ch/archive/2009/09/27/mvvm-light-toolkit-messenger-v2-beta.aspx Cinch de iyi bir örnektir. Paul Stovel iyi sahiptir yazı onun Magellan çerçeve ile de bir çok şeyi açıklıyor.


3

Baktığınız Caliburn ? ContactManager örneğinde çok iyi şeyler var. Jenerik WPF örnekleri ayrıca komutlara iyi bir genel bakış sağlar. Dokümantasyon oldukça iyi ve forumlar aktif. Önerilen!





2

Ben de senin hayal kırıklığını paylaştım. Bir başvuru yazıyorum ve şu 3 gereksinime sahiptim:

  • Genişletilebilir
  • MVVM ile WPF
  • GPL uyumlu örnekler

Tüm bulduğum bitler ve parçalardı, bu yüzden elimden gelenin en iyisini yazmaya başladım. Biraz girdikten sonra, referans uygulamasını kullanabilen başka insanlar da olabileceğini fark ettim, bu yüzden genel malzemeleri bir WPF / MVVM uygulama çerçevesine yeniden düzenledim ve LGPL altında yayınladım. SoapBox Core adını verdim . İndirilenler sayfasına giderseniz, bunun küçük bir demo uygulaması ile geldiğini görürsünüz ve söz konusu demo uygulamasının kaynak kodu da indirilebilir. Umarım faydalı bulursun. Ayrıca, daha fazla bilgi için bana scott {at} soapboxautomation.com adresinden e-posta gönderin.

EDIT : Ayrıca nasıl çalıştığını açıklayan bir CodeProject makale yayınladı .


2

Burada kod projesi üzerinde sıfırdan basit bir MVVM örneği yazdım link MVVM WPF adım adım . Basit 3 katmanlı bir mimariden başlar ve PRISM gibi bir çerçeve kullanmanız için mezun olur.

resim açıklamasını buraya girin


1

Konuyu elime alana kadar hayal kırıklığını bile paylaştım. IncEditor'u başlattım.

IncEditor ( http://inceditor.codeplex.com ) geliştiricileri WPF, MVVM ve MEF ile tanıştırmaya çalışan bir editördür. Başladım ve 'tema' desteği gibi bazı işlevler almayı başardım. WPF veya MVVM veya MEF konusunda uzman değilim, bu yüzden çok fazla işlevsellik koyamıyorum. Benim gibi nutters'ın daha iyi anlayabilmesi için sizleri daha iyi hale getirmeniz için samimi bir istekte bulunuyorum.

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.