Beispiel 1: In meiner MVVM-Anwendung wird eine Ansicht angezeigt (wir verwenden Silverlight für die Zwecke der Diskussion) und ich klicke auf eine Schaltfläche, die mich zu einer neuen Seite führen soll.
Beispiel 2: Dieselbe Ansicht verfügt über eine weitere Schaltfläche, die beim Klicken eine Detailansicht in einem untergeordneten Fenster (Dialogfeld) öffnen soll.
Wir wissen, dass Command-Objekte von unserem ViewModel verfügbar gemacht werden, die an die Schaltflächen mit Methoden gebunden sind, die auf den Klick des Benutzers reagieren. Aber was dann? Wie schließen wir die Aktion ab? Auch wenn wir einen sogenannten NavigationService nutzen, was erzählen wir davon?
Um genauer zu sein, müssten die Command-Objekte in einem herkömmlichen View-first-Modell (wie URL-basierten Navigationsschemata wie im Web oder dem integrierten SL-Navigationsframework) wissen, welche View als Nächstes angezeigt werden soll. Das scheint die Grenze zu überschreiten, wenn es um die Trennung von Bedenken geht, die durch das Muster gefördert werden.
Wenn die Schaltfläche jedoch nicht mit einem Befehlsobjekt verbunden ist und sich wie ein Hyperlink verhält, können die Navigationsregeln im Markup definiert werden. Aber möchten wir, dass die Ansichten den Anwendungsfluss steuern und die Navigation nicht nur eine andere Art von Geschäftslogik ist? (In einigen Fällen kann ich ja und in anderen nein sagen.)
Für mich wäre die utopische Implementierung des MVVM-Musters (und ich habe gehört, dass andere dies behaupten), das ViewModel so zu verdrahten, dass die Anwendung kopflos ausgeführt werden kann (dh keine Views). Dies bietet die größte Oberfläche für codebasierte Tests und macht die Ansichten zu einer echten Skin für die Anwendung. Und meinem ViewModel sollte es egal sein, ob es im Hauptfenster, einem schwebenden Bedienfeld oder einem untergeordneten Fenster angezeigt wird, oder?
Gemäß diesem Apprach ist es einem anderen Mechanismus überlassen, zur Laufzeit zu "binden", welche Ansicht für jedes ViewModel angezeigt werden soll. Aber was ist, wenn wir eine Ansicht mit mehreren ViewModels teilen möchten oder umgekehrt?
In Anbetracht der Notwendigkeit, die View-ViewModel-Beziehung zu verwalten, damit wir wissen, was angezeigt werden soll, und der Notwendigkeit, zwischen Ansichten zu navigieren, einschließlich der Anzeige von untergeordneten Fenstern / Dialogen, wie können wir dies im MVVM-Muster wirklich erreichen?
quelle
DataTemplateSelector
, die ich normalerweise für Silverlight-Apps verwende. 2) Ich habe das schon in vielen Situationen benutzt. Beispielsweise kann ein ViewModel mehrere Ansichten haben, oder eine Ansicht kann mehreren ViewModels zugeordnet sein. Ein Beispiel für Ersteres finden Sie unter rachel53461.wordpress.com/2011/05/28/… . Für die spätere Version müssen Sie nur angeben, dass mehrere ViewModels derselben Ansicht in Ihrem DataTemplateSelector zugeordnet sind.CurrentPages
, dass es mehrere Fenster verarbeiten kann. 4) Auch hier war dies nur ein einfaches Beispiel. In Wirklichkeit basieren meine PageViewModels alle auf einer Basisklasse, sodass mein ShellViewModel nur mit der Basisklasse oder der Schnittstelle funktioniert, zIPageViewModel
. Wirklich die größte Unordnung bei der Zuordnung ist der DataTemplateSelector, der 40 Views auf 40 ViewModels abbilden müsste.Aus Gründen des Abschlusses dachte ich, ich würde die Richtung angeben, die ich letztendlich zur Lösung dieses Problems gewählt habe.
Die erste Entscheidung war, das sofort einsatzbereite Silverlight-Seitennavigations-Framework zu nutzen. Diese Entscheidung beruhte auf mehreren Faktoren, darunter dem Wissen, dass diese Art der Navigation von Microsoft in Windows 8 Metro-Apps übertragen wird und mit der Navigation in Phone 7-Apps übereinstimmt.
Als Nächstes habe ich mir die Arbeit der ASP.NET-MVC mit der konventionellen Navigation angesehen. Das Frame-Steuerelement verwendet URIs, um die anzuzeigende "Seite" zu finden. Die Ähnlichkeit bot die Möglichkeit, einen ähnlichen konventionellen Ansatz in der Silverlight-App zu verwenden. Der Trick bestand darin, dass alles auf MVVM-Weise zusammenarbeitete.
Die Lösung ist der NavigationService. Dieser Dienst stellt verschiedene Methoden zur Verfügung, z. B. NavigateTo und Back, mit denen ViewModels einen Seitenwechsel initiieren können. Wenn eine neue Seite angefordert wird, sendet der Navigationsdienst eine CurrentPageChangedMessage mit der MVVMLight Messenger-Funktion.
Die Ansicht, die das Frame-Steuerelement enthält, verfügt über ein eigenes ViewModel, das als DataContext festgelegt ist, der auf diese Nachricht wartet. Beim Empfang wird der Name der neuen Ansicht einer Zuordnungsfunktion unterzogen, die unsere Konventionsregeln anwendet und auf die CurrentPage-Eigenschaft setzt. Die Source-Eigenschaft des Frame-Steuerelements ist an die CurrentPage-Eigenschaft gebunden. Infolgedessen aktualisiert das Festlegen der Eigenschaft die Quelle und löst die Navigation aus.
Zurück zum Navigationsservice. Die NavigateTo-Methode akzeptiert den Namen der Zielseite. Um sicherzustellen, dass die ViewModels keine Probleme mit der Benutzeroberfläche haben, wird der Name des anzuzeigenden ViewModels verwendet. Ich habe tatsächlich eine Aufzählung erstellt, die ein Feld für jedes navigierbare ViewModel als Helfer und zur Eliminierung magischer Zeichenfolgen in der gesamten App enthält. Die oben erwähnte Zuordnungsfunktion entfernt das Suffix "ViewModel" vom Namen, hängt "Page" an den Namen an und setzt den vollständigen Namen auf "Views {Name} Page.xaml".
Um zum Beispiel zur Kundendetailsicht zu navigieren, kann ich anrufen:
Der Wert von CustomerDetails ist "CustomerDetailsViewModel", der "Views \ CustomerDetailsPage.xaml" zugeordnet ist.
Das Schöne an diesem Ansatz ist, dass die Benutzeroberfläche vollständig von den ViewModels entkoppelt ist, wir jedoch volle Navigationsunterstützung haben. Ich kann meine Anwendung jetzt jedoch reskinen und wann immer ich es für richtig halte, ohne dass sich der Code ändert.
Hoffe die Erklärung hilft.
quelle
Ähnlich wie Rachel es gesagt hat, hat meine hauptsächlich aus MVVM bestehende Anwendung eine Funktion
Presenter
zum Umschalten zwischen Fenstern oder Seiten. Rachel nennt dies einApplicationViewModel
, aber meiner Erfahrung nach muss es im Allgemeinen mehr als nur ein verbindliches Ziel sein (wie das Empfangen von Nachrichten, das Erstellen von Windows usw.), also ist es technisch eher wie ein traditionellesPresenter
oder einController
.In meiner Bewerbung
Presenter
beginnt meine mit einemCurrentViewModel
. DasPresenter
fängt die gesamte Kommunikation zwischen demView
und dem abViewModel
. Eines der Dinge , dieViewModel
während einer Interaktion tun können , ist eine neue zurückgebenViewModel
, was bedeutet , eine neue Seite oder ein neuesWindow
angezeigt werden soll. DasPresenter
kümmert sich darum, dasView
für das Neue zu erstellen oder zu überschreibenViewModel
und das einzustellenDataContext
.Das Ergebnis einer Aktion kann auch sein, dass a
ViewModel
"vollständig" ist. In diesem FallPresenter
erkennt der Benutzer dies und schließt das Fenster oder entfernt esViewModel
vom VM-Stapel und kehrt zur Anzeige der vorherigen Seite zurück.quelle
Presenter
gerade Stöcke des zurückViewModel
in der visuellen Struktur und WPF packt die entsprechendenView
, bis Haken , dieDataContext
, und Puts , dass in der visuellen Struktur statt. Sie können dazuDataTemplate
s verwenden, die deklarieren, welchenViewModel
Typ sie darstellen, oder Sie können einen benutzerdefinierten Datenvorlagen-Selektor erstellen. Das liegt immer noch im Bereich der WPF-Funktionen.