Große intelligente ViewModels, dumme Views und jedes Modell, der beste MVVM-Ansatz?

8

Der folgende Code ist ein Refactoring meines vorherigen MVVM-Ansatzes ( Fat-Modelle, dünne ViewModels und dumme Views, der beste MVVM-Ansatz? ), in denen ich die Logik- und INotifyPropertyChanged-Implementierung vom Modell zurück in das ViewModel verschoben habe. Dies ist sinnvoller, da Sie oft Modelle verwenden, die Sie entweder nicht ändern können oder nicht ändern möchten und mit denen Ihr MVVM-Ansatz arbeiten sollte jede Modellklasse, wie sie existiert.

In diesem Beispiel können Sie noch die Live-Daten Ihres Modells im Design-Modus in Visual Studio und Expression Blend anzeigen . Dies ist wichtig, da Sie einen Scheindatenspeicher haben könnten, mit dem der Designer eine Verbindung herstellt welches hat z die kleinsten und größten Zeichenfolgen, auf die die Benutzeroberfläche möglicherweise trifft, damit er das Design basierend auf diesen Extremen anpassen kann.

Fragen:

  • Ich bin etwas überrascht, dass ich in meinem ViewModel sogar einen "Timer" setzen muss, da es so aussieht, als wäre es eine Funktion von INotifyPropertyChanged, es scheint überflüssig zu sein, aber es war die einzige Möglichkeit, die XAML UI zu bekommen ständig (einmal pro Sekunde) spiegeln den Zustand meines Modells wider. Es wäre also interessant, jemanden zu hören, der diesen Ansatz gewählt hat, wenn Sie auf der Straße irgendwelche Nachteile festgestellt haben, z. mit Threading oder Leistung.

Der folgende Code funktioniert, wenn Sie nur das XAML und den Code in ein neues WPF-Projekt kopieren.

XAML:

%Vor%

Hinterer Code:

%Vor%     
Edward Tanguay 13.05.2009, 13:03
quelle

2 Antworten

13

Ich mag Ihr Beispiel oben, ich denke, es setzt den Geist von MVVM um. Nur zur Verdeutlichung sollten der ViewModel-Code und der Model-Code jedoch nicht in der gleichen Quelldatei wie der eigentliche Code Behind sein. In der Tat würde ich argumentieren, dass sie nicht im selben Projekt sein sollten.

Hier ist MVVM, wie ich es verstehe:

M - Das Modell sind die Daten, die von der Business-Schicht (BL) zurückgegeben werden. Dies sollte leichtgewichtig sein und schreibgeschützte Daten enthalten. Die Model-Klassen sind dumm und enthalten keine Update-, Write- oder Delete-Logik und werden vom BL als Ergebnis von Anfragen, Befehlen, Aktionen usw. generiert. Die Model-Klassen kennen die Präsentationsanforderungen der konsumierenden Anwendung nicht. so können sie bei jeder Art von Anwendung verwendet werden. Um diese Wiederverwendbarkeit wirklich zu nutzen, möchten wir, dass die Model-Klassen unabhängig vom UI-Projekt sind.

VM - das ViewModel enthält die Kommunikationsschicht: Es gibt die Anfragen an die BL aus und verarbeitet die Ergebnisse in einer für die Präsentation geeigneten Weise. Wie im obigen Beispiel empfängt es auch das Modell und formatiert es für die speziellen Darstellungsbedürfnisse neu. Betrachten Sie dies als eine "bindende Klasse". Im obigen Beispiel werden die Daten einfach von einem Objekt zum nächsten verschoben, aber das ViewModel wäre für solche Dinge verantwortlich, wie das Aufdecken einer Eigenschaft vom Typ "FullName" oder das Hinzufügen führender Nullen zu einem ZipCode. Es ist richtig, dass die Bindungsklasse INotifyPropertyChanged implementiert. Und zur Wiederverwendbarkeit würde ich diese Ebene wahrscheinlich auch in ein eigenes Projekt extrahieren. Dies würde es Ihnen ermöglichen, mit verschiedenen UI-Optionen zu experimentieren, ohne Änderungen in der Installation vorzunehmen.

V - Die Ansicht ist an das Binding-Klassenobjekt gebunden, das in der VM erstellt wurde. Die View ist super dumm: Sie weiß nichts von der BL oder der VM. Daten können in beide Richtungen gebunden sein, aber die VM behandelt Fehler, Validierung usw. Alle Datensynchronisationsvorgänge werden durch Weiterleiten von Anforderungen an die BL und erneutes Verarbeiten der Ergebnisse behandelt.

Es hängt von der Art der Anwendung ab, aber es scheint schwer zu sein, das Modell ständig zu überprüfen, um zu sehen, ob es sich geändert hat. Angenommen, Sie würden eine Verbindung zu einer BL herstellen, die das Business-Objekt (BO) von einer DAL erstellt hat, die mit einer DB verbunden ist. In diesem Szenario würden Sie das BO ständig neu erstellen, was sicherlich ein Performance-Killer wäre. Sie könnten ein Checkout-System auf der BL implementieren, das auf Benachrichtigungen gewartet hat, oder Sie haben eine Methode, um den letzten bekannten Zeitpunkt der Änderung mit dem tatsächlichen zu vergleichen, oder Sie könnten den BO auf dem BL zwischenspeichern. Nur ein paar Ideen.

Auch ich sagte oben, dass das Modell leicht sein sollte. Es gibt schwergewichtige Optionen wie CSLA, aber ich bin mir nicht sicher, wie gut sie in die MVVM-Idee passen.

Ich möchte mich nicht als Experte ausgeben, ich habe diese Ideen bisher nur beim Entwurf der Architektur unserer neuen Software studiert. Ich würde gerne eine Diskussion über dieses Thema lesen.

    
Joel Cochran 13.05.2009, 19:19
quelle
3

Meine persönliche Meinung ist, dass Model verwendet werden sollte, um Daten zu laden und zu speichern. ViewModels Verantwortlichkeit besteht darin, zu wissen, wann diese Daten benötigt werden, also Timer in einem ViewModel zu verwenden macht Sinn. Auf diese Weise können Sie Ihr Modell mit einem anderen ViewModel verwenden (für das es möglicherweise ausreicht, Daten nur einmal und nicht jede Sekunde abzurufen).

Wenige Dinge zu beachten:

  • Implementieren Sie Ihr Modell zur Unterstützung Asynchroner Datenabruf (sehr wichtig, wenn Sie Silverlight zielen wollen)
  • Seien Sie vorsichtig beim Aktualisieren der Sammlung aus dem Hintergrundthread (kein Problem in Ihrem Beispiel, aber wenn Sie jemals ObservableCollection verwenden müssen, dann denken Sie daran, dass es nicht aus nicht UI-Threads aktualisiert werden kann, lesen Sie hier mehr )
Jarek Kardas 13.05.2009 13:59
quelle

Tags und Links