Im MVVM-Muster für WPF ist die Behandlung von Dialogen eine der komplexeren Operationen. Da Ihr Ansichtsmodell nichts über die Ansicht weiß, kann die Dialogkommunikation interessant sein. Ich kann zeigen, ICommand
dass beim Aufrufen der Ansicht ein Dialogfeld angezeigt werden kann.
Kennt jemand einen guten Weg, um mit Ergebnissen aus Dialogen umzugehen? Ich spreche von Windows-Dialogen wie MessageBox
.
Eine Möglichkeit, dies zu tun, bestand darin, ein Ereignis im Ansichtsmodell zu haben, das die Ansicht abonnieren würde, wenn ein Dialog erforderlich war.
public event EventHandler<MyDeleteArgs> RequiresDeleteDialog;
Dies ist in Ordnung, bedeutet jedoch, dass für die Ansicht Code erforderlich ist, von dem ich mich fernhalten möchte.
Antworten:
Ich schlage vor, auf die modalen Dialoge der 90er Jahre zu verzichten und stattdessen ein Steuerelement als Overlay (Canvas + absolute Positionierung) zu implementieren, dessen Sichtbarkeit an einen Booleschen Wert in der VM gebunden ist. Näher an einem Ajax-Steuerelement.
Das ist sehr nützlich:
wie in:
Hier ist, wie ich eine als Benutzersteuerung implementiert habe. Durch Klicken auf das 'x' wird das Steuerelement in einer Codezeile im Code des Benutzersteuerelements dahinter geschlossen. (Da ich meine Ansichten in einer EXE-Datei und ViewModels in einer DLL habe, habe ich kein schlechtes Gefühl bei Code, der die Benutzeroberfläche manipuliert.)
quelle
Sie sollten hierfür einen Mediator verwenden. Mediator ist ein allgemeines Entwurfsmuster, das auch als bekannt ist in einigen Implementierungen Messenger bezeichnet wird . Es ist ein Paradigma vom Typ Registrieren / Benachrichtigen und ermöglicht es Ihrem ViewModel und Ihren Ansichten, über einen niedrig gekoppelten Messaging-Mechanismus zu kommunizieren.
Sie sollten sich die Google WPF Disciples-Gruppe ansehen und einfach nach Mediator suchen. Sie werden mit den Antworten sehr zufrieden sein ...
Sie können jedoch damit beginnen:
http://joshsmithonwpf.wordpress.com/2009/04/06/a-mediator-prototype-for-wpf-apps/
Genießen !
Bearbeiten: Die Antwort auf dieses Problem mit dem MVVM Light Toolkit finden Sie hier:
http://mvvmlight.codeplex.com/Thread/View.aspx?ThreadId=209338
quelle
Ein guter MVVM-Dialog sollte:
Leider bietet WPF diese Funktionen nicht an. Das Anzeigen eines Dialogfelds erfordert einen CodeBehind-Aufruf von
ShowDialog()
. Die Window-Klasse, die Dialoge unterstützt, kann in XAML nicht deklariert werden, sodass sie nicht einfach an die gebunden werden kannDataContext
.Um dies zu lösen, habe ich ein XAML-Stub-Steuerelement geschrieben, das sich im logischen Baum befindet und die Datenbindung an a weiterleitet und das Ein-
Window
und Ausblenden des Dialogfelds behandelt. Sie finden es hier: http://www.codeproject.com/KB/WPF/XAMLDialog.aspxEs ist wirklich einfach zu bedienen und erfordert keine merkwürdigen Änderungen an Ihrem ViewModel und erfordert keine Ereignisse oder Nachrichten. Der grundlegende Aufruf sieht folgendermaßen aus:
Sie möchten wahrscheinlich einen Stil hinzufügen, der festgelegt wird
Showing
. Ich erkläre es in meinem Artikel. Ich hoffe das hilft dir.quelle
"Showing a dialog requires a code-behind"
mmm können Sie das in ViewModelIch benutze diesen Ansatz für Dialoge mit MVVM.
Jetzt muss ich nur noch Folgendes aus meinem Ansichtsmodell aufrufen.
quelle
Meine aktuelle Lösung löst die meisten der von Ihnen erwähnten Probleme, ist jedoch vollständig von plattformspezifischen Dingen abstrahiert und kann wiederverwendet werden. Außerdem habe ich keine Code-Behind-Bindung nur mit DelegateCommands verwendet, die ICommand implementieren. Dialog ist im Grunde eine Ansicht - ein separates Steuerelement, das über ein eigenes ViewModel verfügt und im ViewModel des Hauptbildschirms angezeigt wird, jedoch über die DelagateCommand-Bindung von der Benutzeroberfläche ausgelöst wird.
Die vollständige Silverlight 4-Lösung finden Sie hier. Modale Dialoge mit MVVM und Silverlight 4
quelle
Ich hatte eine Weile mit diesem Konzept zu kämpfen, als ich MVVM lernte (noch lernte). Was ich beschlossen habe und was andere meiner Meinung nach bereits entschieden haben, was mir aber nicht klar war, ist Folgendes:
Mein ursprünglicher Gedanke war, dass ein ViewModel ein Dialogfeld nicht direkt aufrufen darf, da es kein Geschäft hat, zu entscheiden, wie ein Dialogfeld angezeigt werden soll. Aus diesem Grund begann ich darüber nachzudenken, wie ich Nachrichten weitergeben könnte, wie ich es in MVP getan hätte (dh View.ShowSaveFileDialog ()). Ich denke jedoch, dass dies der falsche Ansatz ist.
Für ein ViewModel ist es in Ordnung, einen Dialog direkt aufzurufen. Wenn Sie jedoch ein ViewModel testen, bedeutet dies, dass das Dialogfeld entweder während des Tests angezeigt wird oder insgesamt fehlschlägt (dies wurde nie wirklich versucht).
Während des Testens muss also eine "Test" -Version Ihres Dialogfelds verwendet werden. Dies bedeutet, dass Sie für jeden Dialog, den Sie haben, eine Schnittstelle erstellen und entweder die Dialogantwort verspotten oder einen Test verspotten müssen, der ein Standardverhalten aufweist.
Sie sollten bereits eine Art Service Locator oder IoC verwenden, die Sie so konfigurieren können, dass Sie je nach Kontext die richtige Version erhalten.
Mit diesem Ansatz kann Ihr ViewModel weiterhin getestet werden. Je nachdem, wie Sie Ihre Dialoge verspotten, können Sie das Verhalten steuern.
Hoffe das hilft.
quelle
Es gibt zwei gute Möglichkeiten, dies zu tun: 1) einen Dialogdienst (einfach, sauber) und 2) eine unterstützte Ansicht. View Assisted bietet einige nette Funktionen, ist es aber normalerweise nicht wert.
DIALOG-SERVICE
a) eine Dialogdienstschnittstelle wie über einen Konstruktor oder einen Abhängigkeitscontainer:
interface IDialogService { Task ShowDialogAsync(DialogViewModel dlgVm); }
b) Ihre Implementierung von IDialogService sollte ein Fenster öffnen (oder ein Steuerelement in das aktive Fenster einfügen), eine Ansicht erstellen, die dem Namen des angegebenen dlgVm-Typs entspricht (verwenden Sie die Containerregistrierung oder -konvention oder einen ContentPresenter mit typassoziierten DataTemplates). ShowDialogAsync sollte eine TaskCompletionSource erstellen und ihre .Task-Proptery zurückgeben. Die DialogViewModel-Klasse selbst benötigt ein Ereignis, das Sie in der abgeleiteten Klasse aufrufen können, wenn Sie schließen möchten, und in der Dialogansicht beobachten können, um den Dialog tatsächlich zu schließen / auszublenden und die TaskCompletionSource abzuschließen.
b) Rufen Sie zur Verwendung einfach await this.DialogService.ShowDialog (myDlgVm) auf Ihrer Instanz einer von DialogViewModel abgeleiteten Klasse auf. Überprüfen Sie nach dem Warten auf die Rückkehr die Eigenschaften, die Sie Ihrer Dialog-VM hinzugefügt haben, um festzustellen, was passiert ist. Sie brauchen nicht einmal einen Rückruf.
ANSICHT UNTERSTÜTZT
Dadurch hört Ihre Ansicht ein Ereignis im Ansichtsmodell ab. Dies alles könnte in ein Mischverhalten eingepackt werden, um Code-Behind und Ressourcennutzung zu vermeiden, wenn Sie dazu neigen (FMI, Unterklasse "Behavior", um eine Art Blendable-angehängte Eigenschaft für Steroide anzuzeigen). Im Moment machen wir das manuell in jeder Ansicht:
a) Erstellen Sie ein OpenXXXXXDialogEvent mit einer benutzerdefinierten Nutzlast (einer von DialogViewModel abgeleiteten Klasse).
b) Lassen Sie die Ansicht das Ereignis in ihrem OnDataContextChanged-Ereignis abonnieren. Stellen Sie sicher, dass Sie den alten Wert! = Null und im Ereignis Unloaded des Fensters ausblenden und abbestellen.
c) Wenn das Ereignis ausgelöst wird, lassen Sie die Ansicht Ihre Ansicht öffnen, die sich möglicherweise in einer Ressource auf Ihrer Seite befindet, oder Sie können sie gemäß Konvention an anderer Stelle suchen (wie im Dialogdienstansatz).
Dieser Ansatz ist flexibler, erfordert jedoch mehr Arbeit. Ich benutze es nicht viel. Der einzige schöne Vorteil ist die Möglichkeit, die Ansicht beispielsweise physisch in einem Tab zu platzieren. Ich habe einen Algorithmus verwendet, um ihn in die Grenzen des aktuellen Benutzersteuerelements zu setzen, oder wenn er nicht groß genug ist, den visuellen Baum zu durchlaufen, bis ein ausreichend großer Container gefunden wurde.
Auf diese Weise können sich Dialoge in der Nähe des Ortes befinden, an dem sie tatsächlich verwendet werden, nur den Teil der App dimmen, der sich auf die aktuelle Aktivität bezieht, und der Benutzer kann sich innerhalb der App bewegen, ohne die Dialoge manuell wegschieben zu müssen, selbst wenn mehrere Quasi vorhanden sind. Modale Dialoge werden auf verschiedenen Registerkarten oder Unteransichten geöffnet.
quelle
Verwenden Sie einen Befehl zum Einfrieren
quelle
Ich denke, dass die Handhabung eines Dialogs in der Verantwortung der Ansicht liegen sollte, und die Ansicht muss Code enthalten, um dies zu unterstützen.
Wenn Sie die ViewModel-View-Interaktion ändern, um Dialoge zu verarbeiten, ist das ViewModel von dieser Implementierung abhängig. Der einfachste Weg, um dieses Problem zu lösen, besteht darin, die Ansicht für die Ausführung der Aufgabe verantwortlich zu machen. Wenn dies bedeutet, dass ein Dialog angezeigt wird, ist dies in Ordnung, kann aber auch eine Statusmeldung in der Statusleiste usw. sein.
Mein Punkt ist, dass der springende Punkt des MVVM-Musters darin besteht, die Geschäftslogik von der GUI zu trennen. Sie sollten also die GUI-Logik (zum Anzeigen eines Dialogfelds) nicht in der Business-Schicht (dem ViewModel) mischen.
quelle
Eine interessante Alternative ist die Verwendung von Controllern, die für die Anzeige der Ansichten (Dialoge) verantwortlich sind.
Wie dies funktioniert, zeigt das WPF Application Framework (WAF) .
quelle
Warum nicht einfach ein Ereignis in der VM auslösen und das Ereignis in der Ansicht abonnieren? Dies würde die Anwendungslogik und die Ansicht getrennt halten und es Ihnen weiterhin ermöglichen, ein untergeordnetes Fenster für Dialoge zu verwenden.
quelle
Ich habe ein Verhalten implementiert, das eine Nachricht aus dem ViewModel abhört. Es basiert auf der Laurent Bugnion-Lösung, aber da es keinen Code dahinter verwendet und wiederverwendbarer ist, finde ich es eleganter.
So verhält sich WPF so, als würde MVVM sofort unterstützt
quelle
Ich denke, die Ansicht könnte Code enthalten, um das Ereignis aus dem Ansichtsmodell zu behandeln.
Abhängig vom Ereignis / Szenario kann es auch einen Ereignisauslöser geben, der das Anzeigen von Modellereignissen abonniert, und eine oder mehrere Aktionen, die als Antwort aufgerufen werden.
quelle
Ich hatte die gleiche Situation und packte die MessageBox in ein unsichtbares Designer-Steuerelement. Die Details sind in meinem Blog
http://geekswithblogs.net/mukapu/archive/2010/03/12/user-prompts-messagebox-with-mvvm.aspx
Das Gleiche kann auf alle modalen Dialoge, Steuerelemente zum Durchsuchen von Dateien usw. erweitert werden.
quelle
Ich rollte meinen eigenen Fensterlader, der in einer Antwort auf diese Frage beschrieben wurde:
Verwalten mehrerer WPF-Ansichten in einer Anwendung
quelle
Karl Shifflett hat eine Beispielanwendung zum Anzeigen von Dialogfeldern mit dem Service-Ansatz und dem Prism InteractionRequest-Ansatz erstellt.
Ich mag den Service-Ansatz - Er ist weniger flexibel, sodass Benutzer weniger wahrscheinlich etwas kaputt machen :) Er stimmt auch mit dem WinForms-Teil meiner Anwendung (MessageBox.Show) überein. Wenn Sie jedoch viele verschiedene Dialoge anzeigen möchten, ist InteractionRequest eine besserer Weg zu gehen.
http://karlshifflett.wordpress.com/2010/11/07/in-the-box-ndash-mvvm-training/
quelle
Ich weiß, dass es eine alte Frage ist, aber als ich diese Suche durchgeführt habe, habe ich viele verwandte Fragen gefunden, aber ich habe keine wirklich klare Antwort gefunden. Also mache ich meine eigene Implementierung eines Dialogfelds / einer Nachrichtenbox / eines Popins und teile es!
Ich denke, es ist "MVVM-Beweis", und ich versuche, es einfach und richtig zu machen, aber ich bin neu in WPF, also zögern Sie nicht, Kommentare abzugeben oder sogar Pull-Anfragen zu stellen.
https://github.com/Plasma-Paris/Plasma.WpfUtils
Sie können es so verwenden:
Oder so, wenn Sie ein anspruchsvolleres Popin möchten:
Und es zeigt solche Dinge:
quelle
Der Standardansatz
Nachdem ich mich jahrelang mit diesem Problem in WPF befasst hatte, fand ich endlich heraus, wie Dialoge in WPF standardmäßig implementiert werden können. Hier sind die Vorteile dieses Ansatzes:
Also, was ist der Schlüssel. Es ist DI + IoC .
So funktioniert es. Ich verwende MVVM Light, aber dieser Ansatz kann auch auf andere Frameworks erweitert werden:
Fügen Sie dem VM-Projekt eine Schnittstelle IDialogService hinzu :
Stellen Sie eine öffentliche statische Eigenschaft vom
IDialogService
Typ in Ihrem bereitViewModelLocator
, lassen Sie jedoch den Registrierungsteil für die Ansichtsebene. Dies ist der Schlüssel .:Fügen Sie eine Implementierung dieser Schnittstelle in das App-Projekt ein.
ShowMessage
,AskBooleanQuestion
etc.), andere sind spezifisch für dieses Projekt und die Verwendung benutzerdefiniertWindow
s. Sie können auf dieselbe Weise weitere benutzerdefinierte Fenster hinzufügen. Der Schlüssel besteht darin, UI-spezifische Elemente in der Ansichtsebene beizubehalten und die zurückgegebenen Daten mithilfe von POCOs in der VM-Ebene verfügbar zu machen .Führen Sie mit dieser Klasse eine IoC-Registrierung Ihrer Schnittstelle in der Ansichtsebene durch. Sie können dies im Konstruktor Ihrer Hauptansicht tun (nach dem
InitializeComponent()
Aufruf):Los geht's. Sie haben jetzt Zugriff auf alle Dialogfunktionen auf VM- und View-Ebene. Ihre VM-Schicht kann diese Funktionen folgendermaßen aufrufen:
Andere kostenlose Vergünstigungen
IDialogService
in Ihrem Testprojekt bereitstellen und diese Klasse in IoC im Konstruktor Ihrer Testklasse registrieren.Microsoft.Win32
Öffnen und Speichern zugreifen zu können. Ich habe sie weggelassen, da auch eine WinForms-Version dieser Dialoge verfügbar ist und jemand möglicherweise eine eigene Version erstellen möchte. Beachten Sie auch, dass einige der in verwendetenDialogPresenter
Bezeichner Namen meiner eigenen Fenster sind (zSettingsWindow
. ). Sie müssen sie entweder sowohl von der Benutzeroberfläche als auch von der Implementierung entfernen oder Ihre eigenen Fenster bereitstellen.DispatcherHelper.Initialize()
früh im Lebenszyklus Ihrer Anwendung auf.Mit Ausnahme dessen,
DialogPresenter
was in die Ansichtsebene eingefügt wird, sollten andere ViewModals registriertViewModelLocator
und anschließend eine öffentliche statische Eigenschaft dieses Typs für die Ansichtsebene verfügbar gemacht werden . Etwas wie das:Zum größten Teil sollten Ihre Dialoge keinen Code-Behind für Dinge wie das Binden oder Festlegen von DataContext usw. haben. Sie sollten nicht einmal Dinge als Konstruktorparameter übergeben. XAML kann das alles für Sie tun:
DataContext
diese Einstellung vornehmen, erhalten Sie alle möglichen Vorteile für die Entwurfszeit, z. B. Intellisense und automatische Vervollständigung.Hoffe das hilft allen.
quelle
Ich habe über ein ähnliches Problem nachgedacht, als ich gefragt habe, wie das Ansichtsmodell für eine Aufgabe oder einen Dialog aussehen soll .
Meine aktuelle Lösung sieht folgendermaßen aus:
Wenn das Ansichtsmodell entscheidet, dass Benutzereingaben erforderlich sind, ruft es eine Instanz
SelectionTaskModel
mit den möglichen Auswahlmöglichkeiten für den Benutzer auf. Die Infrastruktur sorgt dafür, dass die entsprechende Ansicht angezeigt wird, die dieChoose()
Funktion zum richtigen Zeitpunkt nach Wahl des Benutzers aufruft.quelle
Ich hatte mit dem gleichen Problem zu kämpfen. Ich habe mir eine Möglichkeit ausgedacht, zwischen View und ViewModel zu kommunizieren. Sie können das Senden einer Nachricht vom ViewModel an die Ansicht initiieren, um anzuweisen, dass eine Nachrichtenbox angezeigt werden soll, und das Ergebnis wird gemeldet. Dann kann das ViewModel auf das von der Ansicht zurückgegebene Ergebnis reagieren.
Ich demonstriere dies in meinem Blog :
quelle
Ich habe einen ziemlich umfassenden Artikel zu diesem Thema geschrieben und auch eine Popup-Bibliothek für MVVM-Dialoge entwickelt. Die strikte Einhaltung von MVVM ist nicht nur möglich, sondern bei ordnungsgemäßer Implementierung auch sehr sauber. Sie kann problemlos auf Bibliotheken von Drittanbietern erweitert werden, die sich nicht selbst daran halten:
https://www.codeproject.com/Articles/820324/Implementing-Dialog-Boxes-in-MVVM
quelle
Entschuldigung, aber ich muss mich einschalten. Ich habe einige der vorgeschlagenen Lösungen durchgesehen, bevor ich den Prism.Wpf.Interactivity-Namespace im Prism-Projekt gefunden habe. Sie können Interaktionsanforderungen und Popup-Fensteraktionen verwenden, um entweder ein benutzerdefiniertes Fenster zu rollen, oder für einfachere Anforderungen sind Popups für Benachrichtigung und Bestätigung integriert. Diese erstellen echte Fenster und werden als solche verwaltet. Sie können ein Kontextobjekt mit allen Abhängigkeiten übergeben, die Sie im Dialogfeld benötigen. Wir verwenden diese Lösung bei meiner Arbeit, seit ich sie gefunden habe. Wir haben hier zahlreiche leitende Entwickler und niemand hat sich etwas Besseres ausgedacht. Unsere vorherige Lösung war der Dialogdienst in ein Overlay und die Verwendung einer Präsentationsklasse, um dies zu ermöglichen. Sie mussten jedoch Fabriken für alle Dialogansichtsmodelle usw. haben.
Das ist nicht trivial, aber auch nicht sehr kompliziert. Und es ist in Prisma eingebaut und daher meiner Meinung nach die beste (oder bessere) Praxis.
Meine 2 Cent!
quelle
EDIT: Ja, ich stimme zu, dass dies kein korrekter MVVM-Ansatz ist, und ich verwende jetzt etwas Ähnliches wie das, was von Blindmeis vorgeschlagen wird.
Eine Möglichkeit, dies zu erreichen, ist
In Ihrem Hauptansichtsmodell (wo Sie das Modal öffnen):
Und in Ihrem Modal Window View / ViewModel:
XAML:
ViewModel:
oder ähnlich wie hier veröffentlicht WPF MVVM: So schließen Sie ein Fenster
quelle