web-dev-qa-db-de.com

Gute Beispiele für MVVM-Vorlagen

Ich arbeite derzeit mit der Microsoft MVVM-Vorlage und finde den Mangel an detaillierten Beispielen frustrierend. Das mitgelieferte ContactBook-Beispiel zeigt nur sehr wenige Befehle, und das einzige andere Beispiel, das ich gefunden habe, stammt aus einem MSDN Magazine-Artikel, in dem die Konzepte ähnlich sind, jedoch einen etwas anderen Ansatz verwenden und die Komplexität immer noch fehlt. Gibt es anständige MVVM-Beispiele, die zumindest grundlegende CRUD-Operationen und Dialog-/Inhaltswechsel zeigen?


Alle Vorschläge waren wirklich nützlich und ich werde anfangen, eine Liste guter Ressourcen zusammenzustellen

Frameworks/Templates

Nützliche Artikel

Screencasts

Zusätzliche Bibliotheken

137
jwarzech

Leider gibt es keine großartige MVVM-Beispiel-App, die alles macht, und es gibt viele verschiedene Ansätze, um Dinge zu tun. Zunächst möchten Sie sich vielleicht mit einem der verfügbaren App-Frameworks vertraut machen (Prism ist eine gute Wahl), da es Ihnen praktische Tools wie Abhängigkeitsinjektion, Befehle, Ereignisaggregation usw. bietet, mit denen Sie auf einfache Weise verschiedene Muster ausprobieren können, die zu Ihnen passen .

Die Prismenfreigabe:
http://www.codeplex.com/CompositeWPF

Es enthält eine ziemlich anständige Beispiel-App (der Börsenhändler) sowie viele kleinere Beispiele und Anleitungen. Zumindest ist es eine gute Demonstration einiger gängiger Untermuster, mit denen MVVM tatsächlich funktioniert. Sie haben Beispiele für CRUD und Dialoge, glaube ich.

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

CRUD: Dieser Teil ist ziemlich einfach. Mit Zwei-Wege-Bindungen von WPF können die meisten Daten ganz einfach bearbeitet werden. Der eigentliche Trick besteht darin, ein Modell bereitzustellen, mit dem die Benutzeroberfläche einfach eingerichtet werden kann. 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 möchten möglicherweise auch IDataErrorInfo implementieren. zur Validierung. In der Regel ist das Einrichten von CRUD ein Kinderspiel, wenn Sie eine ORM-Lösung verwenden.

Dieser Artikel beschreibt einfache Rohoperationen: http://dotnetslackers.com/articles/wpf/WPFDataBindingWithLINQ.aspx

Es basiert auf LinqToSql, ist jedoch für das Beispiel nicht relevant. Wichtig ist lediglich, dass Ihre Geschäftsobjekte INotifyPropertyChanged implementieren (welche Klassen von LinqToSql generiert werden). MVVM ist nicht der Sinn dieses Beispiels, aber ich denke nicht, dass es in diesem Fall wichtig ist.

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

Wiederum generieren die meisten ORM-Lösungen Klassen, die IDataErrorInfo bereits implementieren, und bieten in der Regel einen Mechanismus, der das Hinzufügen benutzerdefinierter Validierungsregeln vereinfacht.

In den meisten Fällen können Sie ein von einem ORM erstelltes Objekt (Modell) in ein ViewModel einbinden, das es enthält, und Befehle zum Speichern/Löschen - und Sie können die Benutzeroberfläche direkt an die Modelleigenschaften binden.

Die Ansicht würde ungefähr so ​​aussehen (ViewModel hat eine Eigenschaft Item, die das Modell enthält, wie eine im ORM erstellte Klasse):

<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 etwas knifflig. Ich bevorzuge eine Variante des Mediator-Ansatzes für Dialoge. In dieser StackOverflow-Frage erfahren Sie mehr darüber:
WPF MVVM-Dialogbeispiel

Mein üblicher Ansatz, der nicht ganz klassisch für MVVM ist, lässt sich wie folgt zusammenfassen:

Eine Basisklasse für ein Dialogfeld ViewModel, die Befehle für Festschreibungs- und Abbruchaktionen bereitstellt, ein Ereignis, mit dem die Ansicht darüber informiert wird, dass ein Dialogfeld geschlossen werden kann, und was auch immer Sie in all Ihren Dialogfeldern benötigen.

Eine allgemeine Ansicht für Ihr Dialogfeld - dies kann ein Fenster oder ein benutzerdefiniertes "modales" Overlay-Steuerelement sein. Im Kern handelt es sich um einen Content Presenter, in den wir das ViewModel einfügen, und er übernimmt die Verkabelung zum Schließen des Fensters. Beispielsweise können Sie bei einer Änderung des Datenkontexts überprüfen, ob das neue ViewModel von Ihrer Basisklasse geerbt wurde und ob dies der Fall ist. Abonnieren Sie das relevante Abschlussereignis (der Handler weist das Dialogergebnis zu). Wenn Sie eine alternative universelle Schließfunktion bereitstellen (z. B. die Schaltfläche X), sollten Sie sicherstellen, dass Sie den entsprechenden Schließbefehl auch im ViewModel ausführen.

Irgendwo, wo Sie Datenvorlagen für Ihre ViewModels bereitstellen müssen, können diese sehr einfach sein, zumal Sie wahrscheinlich für jedes Dialogfeld eine Ansicht haben, die in einem separaten Steuerelement gekapselt ist. Die Standarddatenvorlage für ein ViewModel würde dann ungefähr so ​​aussehen:

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

Die Dialogansicht muss Zugriff auf diese haben, da sie sonst nicht weiß, wie das ViewModel angezeigt wird. Abgesehen von der freigegebenen Dialogbenutzeroberfläche sieht der Inhalt im Wesentlichen folgendermaßen aus:

<ContentControl Content="{Binding}" />

Die implizite Datenvorlage ordnet die Ansicht dem Modell zu, aber wer startet sie?

Dies ist der nicht so mvvm Teil. Eine Möglichkeit besteht darin, ein globales Ereignis zu verwenden. Ich denke, es ist besser, ein Ereignisaggregatortyp-Setup zu verwenden, das durch Abhängigkeitsinjektion bereitgestellt wird. Auf diese Weise ist das Ereignis global für einen Container und nicht für die gesamte App. Prism verwendet das Unity-Framework für die Container-Semantik und die Abhängigkeitsinjektion, und insgesamt gefällt mir Unity ziemlich gut.

Normalerweise ist es sinnvoll, dass das Stammfenster dieses Ereignis abonniert. Es kann den Dialog öffnen und den Datenkontext auf das ViewModel setzen, das mit einem ausgelösten Ereignis übergeben wird.

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

Es gibt jedoch Zeiten, in denen die Benutzeroberfläche die Dialoge anheben muss, was die Dinge etwas schwieriger machen kann. Stellen Sie sich zum Beispiel vor, dass die Position des Dialogfelds von der Position der Schaltfläche abhängt, mit der es geöffnet wird. In diesem Fall benötigen Sie einige UI-spezifische Informationen, wenn Sie ein Dialogfeld öffnen möchten. Im Allgemeinen erstelle ich eine separate Klasse, die ein ViewModel und einige relevante UI-Informationen enthält. Leider scheint dort eine Kopplung unvermeidlich.

Pseudocode eines Button-Handlers, der einen Dialog aufruft, der 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 wird an Positionsdaten gebunden und das enthaltene ViewModel an das innere ContentControl übergeben. Das ViewModel selbst weiß immer noch nichts über die Benutzeroberfläche.

Im Allgemeinen verwende ich die DialogResult return -Eigenschaft der ShowDialog() -Methode nicht und 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 möchte man oft nicht, dass ein Event-Handler sowieso so blockiert. Ich ziehe es vor, die ViewModels damit befassen zu lassen - der Ersteller eines ViewModels kann die relevanten Ereignisse abonnieren, Festlegen/Abbrechen-Methoden usw. festlegen, so dass es nicht erforderlich ist, sich auf diesen UI-Mechanismus zu verlassen.

Also statt dieses Flusses:

// 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 bevorzuge es auf diese Weise, weil die meisten meiner Dialoge nicht blockierende pseudomodale Steuerelemente sind und es einfacher erscheint, dies zu tun, als es zu umgehen. Einfach zu Unit-Test.

57
Egor

Jason Dolinger hat einen guten Screencast von MVVM gemacht. Wie Egor erwähnt hat, gibt es kein gutes Beispiel. Sie sind alle vorbei. Die meisten sind gute MVVM-Beispiele, aber nicht, wenn Sie in komplexe Probleme geraten. Jeder hat seinen eigenen Weg. Laurent Bugnion hat eine gute Möglichkeit, auch zwischen Ansichtsmodellen 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 ein gutes post , das auch viel mit seinem Magellan-Framework erklärt.

6
nportelli

Fand dieses nützlich. Hat auch Code.

http://msdn.Microsoft.com/en-us/magazine/dd419663.aspx

3
McBainUK

Hast du dir Caliburn angesehen? Das ContactManager-Beispiel enthält viele nützliche Informationen. Die generischen WPF-Beispiele bieten auch einen guten Überblick über Befehle. Die Dokumentation ist ziemlich gut und die Foren sind aktiv. Empfohlen!

3
Andy S

Ich teilte auch Ihre Frustration. Ich schreibe eine Bewerbung und hatte diese 3 Anforderungen:

  • Erweiterbar
  • WPF mit MVVM
  • GPL-kompatible Beispiele

Alles, was ich fand, waren Kleinigkeiten, also fing ich gerade an, es so gut ich konnte zu schreiben. Nachdem ich mich ein wenig damit befasst hatte, wurde mir klar, dass es möglicherweise andere Personen (wie Sie) geben könnte, die eine Referenzanwendung verwenden könnten. Daher habe ich das generische Material in ein WPF/MVVM-Anwendungsframework überarbeitet und es unter der LGPL veröffentlicht. Ich nannte es SoapBox Core . Wenn Sie auf die Downloadseite gehen, wird eine kleine Demo-Anwendung mitgeliefert. Der Quellcode für diese Demo-Anwendung kann ebenfalls heruntergeladen werden. Ich hoffe, Sie finden das hilfreich. Schicken Sie mir auch eine E-Mail an scott {at} soapboxautomation.com, wenn Sie weitere Informationen wünschen.

[~ # ~] edit [~ # ~] : Veröffentlichte auch einen CodeProject-Artikel , der erklärt, wie es funktioniert.

2
Scott Whitlock

Hier füge ich den Link einer WPF (Inventory Management App) -Anwendung hinzu, die eine von mir entworfene MVVM-Architektur verwendet.

Die Benutzeroberfläche ist fantastisch. https://github.com/shivam01990/InventoryManagement

2

Das Beispielprojekt im Cinch-Framework zeigt grundlegende CRUD- und Navigationswerkzeuge. Es ist ein ziemlich gutes Beispiel für die Verwendung von MVVM und enthält einen mehrteiligen Artikel , der dessen Verwendung und Motivationen erklärt.

2
Reed Copsey

Ich habe ein einfaches MVVM-Beispiel von Grund auf für ein Code-Projekt geschrieben. Hier ist der Link MVVM WPF Schritt für Schritt . Es geht von einer einfachen 3-Schichten-Architektur aus und bietet Ihnen die Möglichkeit, ein Framework wie PRISM zu verwenden.

enter image description here

1

Sogar 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, Entwicklern WPF, MVVM und MEF vorzustellen. Ich habe damit angefangen und es geschafft, einige Funktionen wie die Unterstützung von Themen zu erhalten. Ich bin kein Experte in WPF, MVVM oder MEF, daher kann ich nicht viel Funktionalität in das Programm einbauen. Ich fordere euch aufrichtig auf, es besser zu machen, damit Verrückte wie ich es besser verstehen können.