Grundlegende Konzepte von MVVM - Was sollte ein ViewModel tun?

83

Beim Versuch, die Konzepte von MVVM zu verstehen, habe ich bereits mehrere Blogs gelesen und mir einige Projekte angesehen.

Soweit ich weiß , ist eine Ansicht dumm, sie weiß nur, wie man etwas präsentiert, das an sie weitergegeben wird.

Modelle sind nur die einfachen Daten, und ein ViewModel ist so etwas wie ein Auffüllen zwischen den beiden, dass es Informationen vom Modell abruft und an die Ansicht weitergibt und die Ansicht wissen sollte, wie sie dargestellt werden. Oder umgekehrt: Wenn sich die Informationen in der Ansicht ändern, sollte sie die Änderung an das Modell weitergeben .

Aber ich habe immer noch keine Ahnung, wie ich das Konzept anwenden soll. Kann jemand ein sehr einfaches Szenario erklären, damit ich das Konzept verstehen kann? Ich habe mir bereits mehrere Projekte angesehen, aber es macht immer noch keinen Sinn. Wenn also jemand es in einfachem Englisch schreiben könnte, wäre das schön.

RKM
quelle
2
Ich kann der Aussage nicht zustimmen, dass die Ansicht "nur weiß, wie man etwas präsentiert, das an sie weitergegeben wird". View übernimmt Daten von der VM. Niemand gibt Daten an ihn weiter. Niemand kennt die Sicht. Dies ist ein wichtiger Unterschied zu MVP. In MVP (Sie können sich das als eine einfache WPF-Anwendung mit Codebehind-Logik vorstellen, es ist ein MVP-Muster) ist das Codebehind ein Präsentator, der Daten wie gesagt an View übergibt.
Grigory

Antworten:

144

Ich denke gerne so:

Ansichten sind, wie Sie sagen, dumm. Josh Smith, Autor des wegweisenden und oft verlinkten MSDN-Artikels über MVVM, sagte, dass Ansichten "die Kleidung sind, die Daten tragen". Ansichten enthalten niemals Daten oder bearbeiten diese direkt. Sie sind lediglich an Eigenschaften und Befehle Ihrer Ansichtsmodelle gebunden.

Modelle sind Objekte, die die Domäne Ihrer Anwendung wie in Geschäftsobjekten modellieren . Ist Ihre Anwendung ein Musikgeschäft? Vielleicht sind Ihre Modellobjekte Künstler, Alben und Lieder. Ist Ihre Anwendung ein Organigramm-Browser? Vielleicht sind Ihre Modellobjekte Manager und Mitarbeiter. Diese Modellobjekte beziehen sich nicht auf irgendeine Art von visuellem Rendering, und sie stehen nicht einmal in direktem Zusammenhang mit der Anwendung, in die Sie sie einfügen. Ihre Modellobjekte sollten als eine Familie von Objekten, die irgendeine Art darstellen, für sich genommen völlig sinnvoll sein der Domain. Die Modellschicht enthält normalerweise auch Dinge wie Service-Accessoren.

Dies bringt uns zu Viewmodels. Was sind Sie? Dies sind Objekte, die eine GUI-Anwendung modellierenDies bedeutet, dass sie Daten und Funktionen bereitstellen, die von Ansichten verwendet werden können. Sie definieren die Struktur und das Verhalten der tatsächlichen Anwendung, die Sie erstellen. Für die Modellobjekte ist die Domäne die Domäne, die Sie auswählen (Musikspeicher, Organigramm-Browser usw.). Für das Ansichtsmodell ist die Domäne jedoch eine grafische Anwendung. Ihre Ansichtsmodelle werden das Verhalten und die Daten von allem, was Ihre Anwendung tut, zusammenfassen. Sie werden Objekte und Listen als Eigenschaften sowie Dinge wie Befehle verfügbar machen. Ein Befehl ist nur ein Verhalten (im einfachsten Fall ein Methodenaufruf), das in ein Objekt eingebunden ist, das ihn herumträgt. Diese Idee ist wichtig, da Ansichten durch Datenbindung gesteuert werden, die Objekte mit visuellen Steuerelementen verbindet. In MVVM geben Sie einer Schaltfläche keine Click-Handler-Methode.

Für mich waren die verwirrendsten Dinge die folgenden:

  • Obwohl die Ansichtsmodelle Modelle einer grafischen Anwendung sind, verweisen sie nicht direkt auf visuelle Konzepte oder verwenden diese nicht. Sie möchten beispielsweise keine Verweise auf Windows-Steuerelemente in Ihren ViewModels - diese Dinge werden in der Ansicht angezeigt. ViewModels setzen Daten und Verhaltensweisen einfach Steuerelementen oder anderen Objekten aus, die an sie gebunden werden. Beispiel: Haben Sie eine Ansicht mit einer ListBox? Ihr Ansichtsmodell wird mit ziemlicher Sicherheit eine Sammlung enthalten. Hat Ihre Ansicht Schaltflächen? Ihr Ansichtsmodell wird mit ziemlicher Sicherheit einige Befehle enthalten.
  • Es gibt einige Arten von Objekten, die als "Ansichtsmodelle" betrachtet werden können. Das am einfachsten zu verstehende Ansichtsmodell ist eines, das ein Steuerelement oder einen Bildschirm in einer 1: 1-Beziehung direkt darstellt, wie in "Bildschirm XYZ verfügt über ein Textfeld, ein Listenfeld und drei Schaltflächen. Das Ansichtsmodell benötigt also eine Zeichenfolge, eine Sammlung, und drei Befehle. " Eine andere Art von Objekt, die in die Ansichtsmodellebene passt, ist ein Wrapper um ein Modellobjekt, der ihm Verhalten verleiht und es für eine Ansicht benutzerfreundlicher macht. Hier gelangen Sie zu den Konzepten der "dicken" und "dünnen" Ansichtsmodellebenen. Eine "dünne" Ansichtsmodellebene ist eine Reihe von Ansichtsmodellen, die Ihre Modellobjekte direkt für die Ansichten verfügbar machen. Dies bedeutet, dass die Ansichten direkt an Eigenschaften der Modellobjekte gebunden werden. Dies kann beispielsweise für einfache, schreibgeschützte Ansichten funktionieren. Aber was ist, wenn Sie jedem Objekt ein Verhalten zuordnen möchten? Sie möchten das nicht im Modell, da das Modell nicht mit der Anwendung zusammenhängt, sondern nur mit Ihrer Domain. Sie können es in ein Objekt einfügen, das Ihr Modellobjekt umschließt und verbindungsfreundlichere Daten und Verhaltensweisen bietet. Dieses Wrapper-Objekt wird auch als Ansichtsmodell betrachtet. Wenn Sie es haben, entsteht eine "dickere" Ansichtsmodell-Ebene, in der Ihre Ansichten niemals direkt an irgendetwas in einer Modellklasse gebunden werden. Sammlungen enthalten Ansichtsmodelle, die Modelle umschließen, anstatt nur Modelle selbst zu enthalten. Sie können es in ein Objekt einfügen, das Ihr Modellobjekt umschließt und verbindungsfreundlichere Daten und Verhaltensweisen bietet. Dieses Wrapper-Objekt wird auch als Ansichtsmodell betrachtet. Wenn Sie es haben, entsteht eine "dickere" Ansichtsmodellebene, in der Ihre Ansichten niemals direkt an irgendetwas in einer Modellklasse gebunden werden. Sammlungen enthalten Ansichtsmodelle, die Modelle umschließen, anstatt nur Modelle selbst zu enthalten. Sie können es in ein Objekt einfügen, das Ihr Modellobjekt umschließt und verbindungsfreundlichere Daten und Verhaltensweisen bietet. Dieses Wrapper-Objekt wird auch als Ansichtsmodell betrachtet. Wenn Sie es haben, entsteht eine "dickere" Ansichtsmodellebene, in der Ihre Ansichten niemals direkt an irgendetwas in einer Modellklasse gebunden werden. Sammlungen enthalten Ansichtsmodelle, die Modelle umschließen, anstatt nur Modelle selbst zu enthalten.

Das Kaninchenloch geht tiefer - es gibt viele Redewendungen wie ValueConverters, die MVVM am Laufen halten, und es gibt eine Menge zu beachten, wenn Sie über Dinge wie Mischbarkeit, Tests und das Weitergeben von Daten in Ihrer App nachdenken und dies sicherstellen Jedes Ansichtsmodell hat Zugriff auf das Verhalten, das es benötigt (hier kommt die Abhängigkeitsinjektion ins Spiel), aber hoffentlich ist das Obige ein guter Anfang. Der Schlüssel besteht darin, Ihre visuellen Elemente, Ihre Domäne sowie die Struktur und das Verhalten Ihrer tatsächlichen Anwendung als drei verschiedene Dinge zu betrachten.

Nlawalker
quelle
3
+1 - Ich bin hier gelandet, weil mich ein "Wrapper" ViewModel in einem Beispielcode verwirrt hat. Danke, dass du das für mich
geklärt
1
Tolle Antwort - wünschte ich könnte +10.
Nick Hodges
1
@nlawalker Sehr großartig! Die Doppelbits, die Sie oben kommentiert haben, haben mich sehr lange verwirrt. Viele Artikel und Blogs erzählen nur die "Hauptmerkmale" von MVVM, aber wenn Sie versuchen, damit fertig zu werden, werden die Dinge sehr kompliziert ! Wie "Wie navigiere ich in diesen Ansichten?" "Was ist die angemessene Granularität beim Entwerfen von ViewModels?" "Muss eine Ansicht ein übereinstimmendes ViewModel haben oder kann ein ViewModel in verschiedenen Ansichten wiederverwendet werden?" Ihre Klarstellung über das ViewModel, das aus "Slim VM" und "Thick VM" besteht, ist wirklich sinnvoll! Ich versuche es, es funktioniert gut weit! :)
Klaue
@nlawalker Danke! Und noch eine Frage: Ich habe TreeView und mache TreeViewViewModel. Wenn ich also Methoden wie ExpandTree () in meinem ViewModel erstelle. Ist es richtig?
user2545071
Wow, das ist ein ausgezeichneter Artikel, ziemlich gute Arbeit @nlawalker
Vivek Shukla
25

Anhand dieses unglaublich hilfreichen Artikels als Quelle finden Sie hier eine Zusammenfassung für View , ViewModel und Model .


Aussicht:

  • Die Ansicht ist ein visuelles Element, z. B. ein Fenster, eine Seite, ein Benutzersteuerelement oder eine Datenvorlage. Die Ansicht definiert die in der Ansicht enthaltenen Steuerelemente sowie deren visuelles Layout und Design.

  • Die Ansicht verweist über ihre DataContextEigenschaft auf das Ansichtsmodell . Die Steuerelemente in der Ansicht sind Daten, die an die Eigenschaften und Befehle gebunden sind, die vom Ansichtsmodell verfügbar gemacht werden.

  • Die Ansicht kann das Datenbindungsverhalten zwischen der Ansicht und dem Ansichtsmodell anpassen. Beispielsweise kann die Ansicht Wertkonverter verwenden, um die in der Benutzeroberfläche anzuzeigenden Daten zu formatieren, oder sie kann Validierungsregeln verwenden, um dem Benutzer eine zusätzliche Validierung der Eingabedaten bereitzustellen.

  • Die Ansicht definiert und verarbeitet das visuelle Verhalten der Benutzeroberfläche, z. B. Animationen oder Übergänge, die durch eine Statusänderung im Ansichtsmodell oder über die Interaktion des Benutzers mit der Benutzeroberfläche ausgelöst werden können.

  • Der Code-Behind der Ansicht definiert möglicherweise die UI-Logik, um visuelles Verhalten zu implementieren, das in XAML schwer auszudrücken ist oder das direkte Verweise auf die in der Ansicht definierten spezifischen UI-Steuerelemente erfordert.

ANMERKUNG:
Da das Ansichtsmodell keine expliziten Kenntnisse über die spezifischen visuellen Elemente in der Ansicht haben sollte, sollte sich Code zum programmgesteuerten Bearbeiten visueller Elemente in der Ansicht im Code-Behind der Ansicht befinden oder in einem Verhalten gekapselt sein.


Modell anzeigen:

  • Das Ansichtsmodell ist eine nicht visuelle Klasse und leitet sich nicht von einer WPF- oder Silverlight-Basisklasse ab. Es kapselt die Präsentationslogik, die zur Unterstützung eines Anwendungsfalls oder einer Benutzeraufgabe in der Anwendung erforderlich ist. Das Ansichtsmodell kann unabhängig von der Ansicht und dem Modell getestet werden.

  • Das Ansichtsmodell verweist normalerweise nicht direkt auf die Ansicht. Es implementiert Eigenschaften und Befehle, an die die Ansicht Daten binden kann. Es benachrichtigt die Ansicht über Statusänderungen über Änderungsbenachrichtigungsereignisse über die Schnittstellen INotifyPropertyChangedund INotifyCollectionChanged.

  • Das Ansichtsmodell koordiniert die Interaktion der Ansicht mit dem Modell. Es kann Daten konvertieren oder bearbeiten, so dass sie leicht von der Ansicht verwendet werden können, und zusätzliche Eigenschaften implementieren, die möglicherweise nicht im Modell vorhanden sind. Es kann auch eine Datenvalidierung über die Schnittstellen IDataErrorInfooder INotifyDataErrorInfoimplementieren.

  • Das Ansichtsmodell kann logische Zustände definieren, die die Ansicht für den Benutzer visuell darstellen kann.

HINWEIS:
Alles, was für das logische Verhalten der Anwendung wichtig ist, sollte in das Ansichtsmodell aufgenommen werden. Code zum Abrufen oder Bearbeiten von Datenelementen, die in der Ansicht durch Datenbindung angezeigt werden sollen, sollte sich im Ansichtsmodell befinden.


Modell:

  • Modellklassen sind nicht visuelle Klassen, die die Daten und die Geschäftslogik der Anwendung kapseln. Sie sind dafür verantwortlich, die Daten der Anwendung zu verwalten und ihre Konsistenz und Gültigkeit sicherzustellen, indem sie die erforderlichen Geschäftsregeln und die Datenvalidierungslogik einkapseln.

  • Die Modellklassen verweisen nicht direkt auf die Ansicht oder die Ansichtsmodellklassen und sind nicht davon abhängig, wie sie implementiert werden.

  • Die Modellklassen stellen normalerweise Benachrichtigungsereignisse für Eigenschafts- und Sammlungsänderungen über die Schnittstellen INotifyPropertyChangedund INotifyCollectionChangedbereit. Dies ermöglicht es ihnen, einfach Daten in der Ansicht zu binden. Modellklassen, die Sammlungen von Objekten darstellen, werden normalerweise von der ObservableCollection<T>Klasse abgeleitet.

  • Die Modellklassen bieten normalerweise Datenvalidierung und Fehlerberichterstattung über die IDataErrorInfooder die INotifyDataErrorInfoSchnittstellen.

  • Die Modellklassen werden normalerweise in Verbindung mit einem Dienst oder Repository verwendet, das den Datenzugriff und das Caching kapselt.

Dom
quelle
17

Ich habe dies in ungefähr so ​​"einfachem Englisch" geschrieben, wie ich es mir in dieser Serie auf MVVM vorstellen kann . Insbesondere ist dieses Diagramm wahrscheinlich die einfachste, kurze Erklärung.

Das "Modell" sind jedoch im Grunde Ihre Daten oder Geschäftsregeln. Es sollte wirklich nicht wissen, wie oder wo es verwendet wird, und insbesondere nicht, welche Technologie es verwenden wird. Das "Modell" ist der Kern der Anwendung - und es sollte sich keine Gedanken darüber machen müssen, ob es sich bei der Anwendung um WPF, Silverlight, Windows Forms, ASP.NET usw. handelt - es ist nur "sich selbst" in reiner Form.

Die "Ansicht" ist der Teil, der vollständig technologiespezifisch ist. In MVVM sollte die Ansicht idealerweise nahezu 100% XAML sein, da dies einige enorme Vorteile für die Flexibilität bietet.

Es muss jedoch etwas geben, das die Informationen aus dem Modell in eine Form übersetzt, in der sie von der jeweiligen Technologie verwendet werden können - hier kommt das ViewModel ins Spiel. Dies "verpackt" beispielsweise häufig die Modellklassen in ein "ViewModel" für diese spezifischen Daten, die Befehle (zum Ausführen von Logik), Implementierungen INotifyPropertyChanged(zur Unterstützung der Datenbindung) usw. enthalten. Das war's - es ist die Brücke, die das Modell erstellt verwendbar durch die Ansicht.

Reed Copsey
quelle
OK danke. Ich stellte mir das Modell als Objekte und ViewModel als Methoden zur Behandlung der Objekte vor, sodass eine Ansicht die "Objekte" des Modells verstehen kann. Aber mir wurde gesagt, dass dies falsch ist, dass das ViewModel selbst auch Objekte sind. Ich denke, das ist es, was mich wirklich verwirrt.
RKM
@Rosie: Ich würde empfehlen, meine von mir zitierte Serie zu lesen (oder zumindest zu überfliegen). Ich habe es speziell geschrieben, weil es nur wenige (fast keine) Artikel über MVVM gibt, die nicht davon ausgehen, dass Sie MVC oder MVP usw. verstehen. Es ist wirklich ein "Schritt für Schritt" -Übergang;)
Reed Copsey
Zu erkennen, dass dies ein wenig Zombie-Threading ist ... Ihr Diagramm besagt, dass die VM "Anwendungsspezifischer Status und Logik " enthält (mein Schwerpunkt). Bedeutet dies, dass Sie der Meinung sind, dass die VM Daten-QS-Logik enthalten könnte / sollte? Das zugehörige RssWpfMVVM.csproj scheint in seinen beiden Ansichtsmodellen keine offensichtliche Qualitätssicherung zu haben.
Ruffin
1

Eine großartige Einführung in MVVM finden Sie in Jason Dolingers Video hier . Ich habe das Video eine ganze Weile bei mir behalten, als ich anfing, es ist wirklich nützlich.

Filipe Miguel
quelle
1
Die Verbindung ist tot
ibrahim mahrir
1
@ibrahimmahrir ~ Ich habe den Link zu einer funktionierenden URL aktualisiert. Ich lade das Video jetzt herunter.
InteXX
0

Das Erstellen eines ViewModel, das eine konsistente Fassade über dem zugrunde liegenden Modell darstellt, kann viel komplexer sein, als es aussieht. Dieser Artikel zum Erstellen von ViewModel-Objekten zeigt, wie ein ViewModel erstellt wird, und zeigt einige der Probleme auf, auf die Sie wahrscheinlich stoßen - zusammen mit vernünftigen Lösungen. Als ich es las, fehlte der Abschnitt über den Umgang mit Sammlungen, aber er enthält noch einige interessante Punkte.

Sprotty
quelle