2009-11-02 1 views
129

Ich arbeite derzeit mit der Microsoft MVVM Vorlage und finde den Mangel an detaillierten Beispielen frustrierend. Das enthaltene ContactBook-Beispiel zeigt sehr wenig Befehlsverarbeitung und das einzige andere Beispiel, das ich gefunden habe, stammt aus einem MSDN Magazine-Artikel, in dem die Konzepte ähnlich sind, aber einen etwas anderen Ansatz verwenden und immer noch in keiner Komplexität fehlen. Gibt es anständige MVVM-Beispiele, die zumindest grundlegende CRUD-Operationen und Dialog-/Inhaltswechsel zeigen?Gute Beispiele für MVVM Template


Vorschläge von allen waren wirklich nützlich und ich werde beginnen, eine Liste von guten Ressourcen

Frameworks/Templates

Nützliche Artikel

Screen

Weitere Bibliotheken

+0

Ich bin froh, dass diese Ressourcen geholfen haben. Ich bin gerade dabei, meine zweite MVVM-Anwendung zu erstellen und werde weiterhin Inhalte hinzufügen, die für diejenigen hilfreich sein werden, die damit anfangen, wenn ich darauf stoße. – jwarzech

Antwort

54

Leider gibt es keine großartige MVVM-Beispiel-App, die alles tut, und es gibt viele verschiedene Ansätze, Dinge zu tun. Zuerst möchten Sie sich vielleicht mit einem der App-Frameworks da draußen vertraut machen (Prism ist eine gute Wahl), da sie Ihnen bequeme Tools wie Dependency-Injection, Commanding, Event-Aggregation usw. zur Verfügung stellen, damit Sie verschiedene Muster ausprobieren können .

Das Prisma Release:
http://www.codeplex.com/CompositeWPF

Es enthält ein recht ordentliches Beispiel app (die Aktienhändler) zusammen mit einer Menge kleinerer Beispiele und wie man ist. Zumindest ist es eine gute Demonstration von mehreren gängigen Sub-Patterns, die Menschen verwenden, um MVVM tatsächlich arbeiten zu lassen. Sie haben Beispiele für CRUD und Dialoge, glaube ich.

Prism ist nicht unbedingt für jedes Projekt, aber es ist eine gute Sache, sich damit vertraut zu machen.

CRUD: Dieser Teil ist ziemlich einfach, WPF-Zwei-Wege-Bindungen machen es wirklich einfach, die meisten Daten zu bearbeiten. Der eigentliche Trick besteht darin, ein Modell bereitzustellen, das die Einrichtung der Benutzeroberfläche erleichtert. Zumindest möchten Sie sicherstellen, dass Ihr ViewModel (oder Geschäftsobjekt) INotifyPropertyChanged implementiert, um die Bindung zu unterstützen, und Sie können Eigenschaften direkt an UI-Steuerelemente binden, aber Sie können auch IDataErrorInfo für die Validierung implementieren. Wenn Sie eine Art von ORM-Lösung verwenden, ist das Einrichten von CRUD in der Regel ein Kinderspiel.

Dieser Artikel beschreibt einfache CRUD-Operationen: http://dotnetslackers.com/articles/wpf/WPFDataBindingWithLINQ.aspx

Es auf LinqToSql gebaut wird, aber das ist zum Beispiel irrelevant - das alles ist wichtig, dass Ihre Business-Objekte INotifyPropertyChanged implementieren (die von LinqToSql tun generierten Klassen) . MVVM ist nicht der Punkt dieses Beispiels, aber ich denke nicht, dass es in diesem Fall eine Rolle spielt.

Dieser Artikel beschreibt die Datenvalidierung
http://blogs.msdn.com/wpfsdk/archive/2007/10/02/data-validation-in-3-5.aspx

Auch die meisten ORM Lösungen Klassen generieren, die bereits IDataErrorInfo implementieren und in der Regel einen Mechanismus bereitstellen, um es benutzerdefinierte Validierungsregeln machen einfach hinzuzufügen.Die meiste Zeit können Sie ein Objekt (Modell), das von einem ORM erstellt wurde, in ein ViewModel mit Speichern und Löschen kopieren - und Sie können die Benutzeroberfläche direkt an die Eigenschaften des Modells binden.

Der Blick aussehen würde so etwas wie (Ansichtsmodell eine Eigenschaft hat Item, die das Modell in der ORM erstellt, wie eine Klasse hält):

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

Dialoge: Dialoge und MVVM sind ein bisschen schwierig. Ich bevorzuge den Geschmack des Mediator-Ansatzes mit Dialogen verwenden, müssen Sie ein wenig mehr über sie in dieser Stackoverflow Frage lesen:
WPF MVVM dialog example

Meinen üblichen Ansatz, der nicht ganz klassische MVVM ist, läßt sie wie folgt zusammenfassen:

Eine Basisklasse für ein Dialog-ViewModel, die Befehle für Commit- und Cancel-Aktionen bereitstellt, ein Ereignis, das der Ansicht anzeigt, dass ein Dialogfeld geschlossen werden kann und was Sie sonst noch in allen Dialogen benötigen.

Eine generische Ansicht für Ihr Dialogfeld - dies kann ein Fenster oder ein benutzerdefiniertes "modales" Overlay-Steuerelement sein. Im Kern ist es ein Content-Presenter, in den wir das Viewmodel ablegen, und es übernimmt die Verkabelung zum Schließen des Fensters. Beispielsweise können Sie bei Änderungen des Datenkontexts überprüfen, ob das neue ViewModel von Ihrer Basisklasse geerbt wurde. abonnieren Sie das entsprechende Close-Event (der Handler wird das Dialog-Ergebnis zuweisen). Wenn Sie eine alternative universelle Schließfunktionalität bereitstellen (z. B. die X-Schaltfläche), sollten Sie sicherstellen, dass der entsprechende Schließbefehl auch im ViewModel ausgeführt wird.

Irgendwo müssen Sie Datenvorlagen für Ihre ViewModels bereitstellen, sie können sehr einfach sein, besonders da Sie wahrscheinlich eine Ansicht für jeden in einem separaten Steuerelement eingekapselten Dialog haben. Die Standard-Datenvorlage für ein Ansichtsmodell würde dann wie folgt aussehen:

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

Die Dialog Ansicht Zugriff auf diese haben muss, denn sonst wird es nicht wissen, wie das Ansichtsmodell zeigen, abgesehen von dem gemeinsamen Dialog UI Sein Inhalt ist im Grunde folgendes:

<ContentControl Content={Binding} /> 

Die implizite Datenvorlage wird die Ansicht dem Modell zuordnen, aber wer startet es?

Dies ist der Nicht-so-MVVM-Teil. Eine Möglichkeit besteht darin, ein globales Ereignis zu verwenden. Was ich denke, ist eine bessere Sache, die Verwendung eines Ereignisaggregator-Typ-Setups, das durch Dependency-Injection bereitgestellt wird - auf diese Weise ist das Ereignis global für einen Container, nicht für die gesamte App. Prism verwendet das Einheits-Framework für Containersemantik und Abhängigkeitsinjektion, und insgesamt mag ich Unity ziemlich.

Normalerweise ist es für das Stammfenster sinnvoll, dieses Ereignis zu abonnieren - es kann den Dialog öffnen und seinen Datenkontext auf das ViewModel setzen, das mit einem erhöhten Ereignis übergeben wird.

Wenn Sie dies auf diese Weise konfigurieren, fordert ViewModels die Anwendung auf, einen Dialog zu öffnen und dort auf Benutzeraktionen zu reagieren, ohne etwas über die Benutzeroberfläche zu wissen. Daher bleibt die MVVM-Funktion größtenteils erhalten.

Es gibt jedoch Zeiten, in denen die Benutzeroberfläche die Dialoge erhöhen muss, was die Dinge ein wenig komplizierter machen kann. Stellen Sie sich beispielsweise vor, ob die Position des Dialogfelds von der Position der Schaltfläche abhängt, die es öffnet.In diesem Fall benötigen Sie einige benutzerspezifische Informationen, wenn Sie ein geöffnetes Dialogfeld anfordern. Ich erstelle normalerweise eine separate Klasse, die ein ViewModel und einige relevante UI-Informationen enthält. Leider scheint dort eine Kopplung unvermeidbar.

Pseudocode eines Taste-Handler, der einen Dialog hebt die Elementpositionsdaten benötigt:

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 
} 

Die Dialogansicht Positionsdaten binden wird, und übergibt das enthaltene Ansichtsmodell an die inneren ContentControl. Das ViewModel selbst weiß immer noch nichts über die Benutzeroberfläche.

Im Allgemeinen verwende ich die DialogResult Rückgabeeigenschaft der ShowDialog() Methode nicht oder erwarte, dass der Thread blockiert, bis das Dialogfeld geschlossen wird. Ein nicht-standardmäßiger modaler Dialog funktioniert nicht immer so, und in einer zusammengesetzten Umgebung wollen Sie nicht wirklich, dass ein Event-Handler sowieso so blockt. Ich bevorzuge es, die ViewModels damit umgehen zu lassen - der Ersteller eines ViewModels kann seine relevanten Ereignisse abonnieren, Commit/Cancel-Methoden festlegen usw., so dass man sich nicht auf diesen UI-Mechanismus verlassen muss.

Statt dieser Strömung:

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

Ich benutze:

// 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 

ich es auf diese Weise bevorzugen, weil die meisten meiner Dialoge nicht blockierende Pseudo-modal Kontrollen sind und es auf diese Weise tun scheint einfacher zu sein als um ihn herum zu arbeiten. Einfach zu Unit-Test als auch.

+0

Danke für die ausführliche Antwort! Ich habe kürzlich festgestellt, dass mein größtes Problem ist, wenn ich ein MainViewModel mit anderen Ansichtsmodellen kommunizieren muss, um den Fluss der Anwendung zu handhaben. Es scheint jedoch, dass MVVM + Mediator der beliebte Ansatz zu sein scheint. – jwarzech

+2

Der Mediator hilft definitiv, das Event-Aggregator-Muster (Prism hat eine gute Implementierung) ist auch sehr hilfreich, wenn eine geringe Kopplung ein Ziel ist. Außerdem hat Ihr Hauptansichtsmodell in der Regel eigene Ansichtsmodelle und sollte keine Probleme bei der Kommunikation mit ihnen haben. Sie müssen einen Mediator oder/und Ereignisaggregator verwenden, wenn Ihre Kindsichtmodelle mit anderen Modulen in Ihrer App interagieren müssen, über die sie nicht unbedingt Bescheid wissen - einschließlich der Benutzeroberfläche (in meinem Dialogbeispiel geht es um diesen speziellen Fall). – Egor

+1

Die Richtlinien zum Arbeiten mit Dialogen und Fenstern waren sehr hilfreich. Ich habe jedoch einige Probleme: 1. Wie stellen Sie den Fenstertitel aus der Ansicht ein? 2. Wie gehen Sie mit der Einstellung des Eigentümerfensters um? – djskinner

2

Das Beispielprojekt in der Cinch framework Grund CRUD und Navigations-Tools zeigt. Es ist ein ziemlich gutes Beispiel für die Verwendung von MVVM und enthält eine multi-part article, die seine Verwendung und Motivationen erklärt.

3

Haben Sie sich Caliburn angesehen? Das ContactManager-Beispiel enthält eine Menge guter Dinge. Die generischen WPF-Beispiele bieten außerdem einen guten Überblick über die Befehle. Die Dokumentation ist ziemlich gut und die Foren sind aktiv. Empfohlen!

2

Ich teilte auch in Ihrer Frustration. Ich bin eine Anwendung schreiben, und ich hatte diese drei Anforderungen:

  • Extensible
  • WPF mit MVVM
  • GPL kompatibel Beispiele

Alles, was ich waren Stücke gefunden, so dass ich gerade erst begonnen Ich schreibe es so gut ich konnte. Nachdem ich mich ein wenig damit beschäftigt hatte, wurde mir klar, dass andere Leute (wie Sie) eine Referenzanwendung verwenden könnten, also habe ich die generischen Sachen in ein WPF/MVVM-Anwendungsframework umgestaltet und unter der LGPL veröffentlicht. Ich nannte es SoapBox Core. Wenn Sie auf die Download-Seite gehen, sehen Sie, dass es mit einer kleinen Demo-Anwendung geliefert wird. Der Quellcode für diese Demo-Anwendung steht ebenfalls zum Download bereit. Ich hoffe, Sie finden das hilfreich. Schicken Sie mir auch eine E-Mail an scott {at} soapboxautomation.com, wenn Sie weitere Informationen wünschen.

BEARBEITEN: Auch eine CodeProject article, die erläutert, wie es funktioniert.

6

Jason Dolinger machte eine gute screencast von MVVM. Wie Egor erwähnt, gibt es kein gutes Beispiel. Sie sind alle vorbei. Die meisten sind gute MVVM-Beispiele, aber nicht, wenn Sie auf komplexe Probleme stoßen. Jeder hat seinen eigenen Weg. Laurent Bugnion hat eine gute Möglichkeit, zwischen Viewmodels zu kommunizieren. http://blog.galasoft.ch/archive/2009/09/27/mvvm-light-toolkit-messenger-v2-beta.aspx Cinch ist auch ein gutes Beispiel. Paul Stovel hat eine gute post, die auch viel mit seinem Magellan-Framework erklärt.

1

Auch ich teilte die Frustration, bis ich die Angelegenheit in meine Hände nahm. Ich habe IncEditor gestartet.

IncEditor (http://inceditor.codeplex.com) ist ein Editor, der versucht, Entwickler zu WPF, MVVM & MEF einzuführen. Ich habe es angefangen und einige Funktionen wie "Theme" Unterstützung bekommen. Ich bin kein Experte in WPF oder MVVM oder MEF, also kann ich nicht viel Funktionalität hineinbringen. Ich bitte euch aufrichtig, es besser zu machen, damit Verrückte wie ich es besser verstehen.

0

Ich habe ein einfaches MVVM Beispiel von Grunde auf Projekt-Code geschrieben hier ist der Link MVVM WPF step by step. Es beginnt mit einer einfachen 3-Layer-Architektur und führt Sie zu einem Framework wie PRISM.

enter image description here