webentwicklung-frage-antwort-db.com.de

WPF (MVVM): Schließen einer Ansicht aus dem Viewmodel?

Hat jemand eine clevere Möglichkeit, eine Ansicht in einem Ansichtsmodell mit MVVM zu schließen?

Möglicherweise gibt es eine Möglichkeit, die Sicht (Fenster) mithilfe des Bindens zu schließen.

Ich würde mich wirklich über jeden Input freuen, den jemand hat.

Im Grunde habe ich eine loginView, die an ein loginViewModel gebunden ist. Im viewmodel (mithilfe der Bindung eines Befehls) teste ich, ob die Anmeldung erfolgreich ist. Wenn dies der Fall ist, lade ich grundsätzlich eine neue Ansicht (mainview) und füge ihren Datenkontakt hinzu. .. 

aber ich habe immer noch das loginView gezeigt - also muss ich es zum entladen signalisieren ..

Ich habe auch auf eine generische Lösung gehofft, weil ich mir sicher bin, dass ich in anderen Situationen so etwas tun muss

Irgendwelche Ideen?

46
mark smith

Edit: Siehe mein Blogbeitrag für eine detailliertere Erklärung.

Wenn ich das erreichen muss, verwende ich eine von mir erstellte IRequestCloseViewModel-Schnittstelle. 

Diese Schnittstelle enthält nur ein Ereignis: RequestClose. Dieses Ereignis wird vom ViewModel ausgelöst (das von einer ViewModelBase-Klasse UND dem IRequestCloseViewModel-Objekt erbt), wenn die zugehörige Ansicht geschlossen werden soll.

In meiner App erben alle Fenster von einer abstrakten Klasse ApplicationWindow. Diese abstrakte Klasse wird bei jeder Änderung des DataContext-Objekts benachrichtigt und überprüft im Handler, ob der DataContext das IRequestCloseViewModel unterstützt. Wenn dies der Fall ist, wird ein Ereignishandler eingerichtet, der das Fenster schließt, wenn das Ereignis ausgelöst wird.

Alternativ können Sie, wie Kent sagte, einen Bildschirmcontroller verwenden, der diesen Mechanismus in einer externen Klasse handhabt.

35
japf

Sie sind sich nicht sicher, welches MVVM-Framework Sie verwenden, aber die meisten enthalten eine Art von Benachrichtigungs-/Benachrichtigungslösung, die sich leicht für die gesendeten Nachrichten registrieren lässt. Es gibt keinen Grund, warum ich mir vorstellen kann, dass Ihre Ansicht sich nicht für eine Nachricht wie "CloseWindowsBoundTo" und das viewModel als Absender registrieren konnte. Dann können Sie sich aus Ihrer Sicht einfach für diese Nachricht registrieren und Ihren aktuellen Datenkontakt mit dem Absender vergleichen. Wenn sie übereinstimmen, schließen Sie das Fenster.

Einfach und hält Ihre Ansicht von Ihrem Ansichtsmodell abstrahiert.

Hier wäre mein Ansatz mit dem MVVM-Light-Toolkit:

Im ViewModel:

public void notifyWindowToClose()
{
    Messenger.Default.Send<NotificationMessage>(
        new NotificationMessage(this, "CloseWindowsBoundToMe")
    );
}

Und im Blick:

Messenger.Default.Register<NotificationMessage>(this, (nm) =>
{
    if (nm.Notification == "CloseWindowsBoundToMe")
    {
        if (nm.Sender == this.DataContext)
            this.Close();
    }
});
22

Ich weiß, dass dies eine alte Frage ist, aber ich habe eine nette Art, dies zu tun, also dachte ich, ich würde es für jeden anderen teilen, der darüber stolpert. Ich habe früher das Dialogcloser-Verhalten verwendet, aber ich finde die Lösung unten einfacher, wo ich sie verwenden kann. Das folgende Beispiel zeigt zur Vereinfachung ein Beispiel für eine Schließen-Schaltfläche im Fenster.

Übergeben Sie das Fenster als Befehlsparameter.

in der Schaltfläche xaml für die Ansicht:

CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"

in der Befehlsausführungsmethode im Ansichtsmodell:

if (parameter is System.Windows.Window)
{
    (parameter as System.Windows.Window).Close();
}
8
cjmurph

Im Allgemeinen würden Sie eine Art Controller/Presenter/Dienst verwenden, um die Aktivierung/Deaktivierung des Bildschirms zu steuern. MVVM soll nicht das One Pattern sein, um sie alle zu regieren . Sie müssen es mit anderen Mustern in einer nicht trivialen Anwendung kombinieren.

Das heißt, in einigen Situationen ist es sinnvoll, ein Ansichtsmodell zu haben, das den Lebenszyklus von untergeordneten Ansichtsmodellen verwaltet. Beispielsweise haben Sie möglicherweise eine EditorViewModel, die eine Sammlung untergeordneter Ansichtsmodelle verwaltet - eines für jedes zu bearbeitende Dokument. In diesem Fall kann durch einfaches Hinzufügen/Entfernen zu dieser Sammlung die Ansicht aktiviert/deaktiviert werden. Das klingt jedoch nicht so, als würde es zu Ihrem Anwendungsfall passen.

8
Kent Boogaart

http://adammills.wordpress.com/2009/07/01/window-close-from-xaml/

<Style.Triggers> <DataTrigger Binding="{Binding CloseSignal}" Value="true"> <Setter Property="Behaviours:WindowCloseBehaviour.Close" Value="true" /> </DataTrigger> </Style>

7
Adam Mills

Sie können einen Befehl erstellen, der an das Fenster angehängt wird und das Fenster schließt, wenn es ausgeführt wird. Dann können Sie diesen Befehl an eine Eigenschaft in Ihrem Ansichtsmodell binden und den Befehl ausführen, wenn Sie das Fenster schließen möchten.

4
user231521

Ich würde einen ApplicationController verwenden, der das LoginViewModel instanziiert und das LoginView anzeigt. Wenn der Benutzer mit dem Anmeldebildschirm fortfährt, schließt der ApplicationController das LoginView und zeigt das MainView mit seinem MainViewModel an.

Wie dies möglich ist, zeigen die Beispielanwendungen des WPF Application Framework (WAF) - Projekts.

2
jbe

Schließen Sie in einem EventHandler einfach den Code dahinter und erledigen Sie alles andere im Ansichtsmodell, in dem Sie eine Befehlsbindung verwenden können.

2
Tarion

Diese Antwort zeigt einen anderen Weg, dies zu tun:

Wie soll das ViewModel das Formular schließen?

Es verwendet eine angefügte Eigenschaft, um die DialogResult-Fenstereigenschaft an eine ViewModel-Eigenschaft zu binden. Wenn Sie den Wert von DialogResult auf true oder false setzen, wird die Ansicht geschlossen.

2
Jorge Vargas

Sie können dies auch mit event tun. Sie benötigen zwar 3 Zeilen Code in Ihrem Ansichtscode (einige MVVM-Puristen mögen das nicht).

In Ihrem Ansichtsmodell erstellen Sie ein Ereignis, das die Ansicht abonnieren kann:

    public event CloseEventHandler Closing;
    public delegate void CloseEventHandler();
    private void RaiseClose()
    {
        if (Closing != null)
            Closing();
    }

In Ihrer Ansicht abonnieren Sie das Ereignis nach der Methode initializecomponent wie folgt:

        public View
        {
           *//The event can be put in an interface to avoid direct dependence of the view on the viewmodel. So below becomes
            //ICloseView model = (ICloseView)this.DataContext;*
            ProgressWindowViewModel model = (ProgressWindowViewModel)this.DataContext;
            model.Closing += Model_Closing;
        }
        private void Model_Closing()
        {
             this.Close();
        }

Sie rufen einfach RaiseClose () an, wenn Sie die Ansicht aus dem ViewModel schließen möchten.

Sie können diese Methode sogar verwenden, um eine Nachricht vom Ansichtsmodell an die Ansicht zu senden.

Das Ereignis kann in eine Schnittstelle eingefügt werden, um eine direkte Abhängigkeit der Ansicht vom Ansichtsmodell zu vermeiden.

1
falopsy

Um die Ansicht aus dem Viewmodel zu schließen, habe ich das Galasoft MVVM Light Toolkit verwendet, das Sie hier herunterladen können: http://www.mvvmlight.net/

  1. erstellen Sie eine Klasse wie folgt: public class ClosingRequested: MessageBase {}

  2. fügen Sie dies Ihrem Ansichtskonstruktor hinzu: Messenger.Default.Register (this, vm, msg => Close ());

  3. rufen Sie dies auf, um das Fenster zu schließen: Messenger.Default.Send (new ClosingRequested (), this);

0
Mick3y