2009-09-27 15 views
46

Qualcuno trova un modo intelligente di chiudere una vista in un modello di vista usando MVVM?WPF (MVVM): chiusura di una vista da Viewmodel?

Forse c'è un modo di usare il binding per segnalare alla vista (finestra) di chiudere?

Apprezzerei molto qualsiasi input che qualcuno ha.

Fondamentalmente ho un loginView che è associato a un loginViewModel, nel viewmodel (usando l'associazione su un comando) eseguo il test per vedere se l'accesso è riuscito e se fondamentalmente sto caricando una nuova vista (vista principale) e allegare la sua DataContext ...

ma ho ancora il LoginView mostrato - quindi ho bisogno di segnalarlo per scaricare ..

ero anche sperando in una soluzione generica, perché sono sicuro che sto andando ad avere bisogno fare questo genere di cose in altre situazioni

Qualche idea?

risposta

35

Modifica: Vedere my blog post per una spiegazione più dettagliata.

Quando ho bisogno di farlo, uso un'interfaccia IRequestCloseViewModel che ho creato.

Questa interfaccia contiene solo un evento: RequestClose. Questo evento viene generato da ViewModel (che eredita da una classe ViewModelBase E implementa IRequestCloseViewModel) quando vuole chiudere la vista associata.

Nella mia app, tutte le finestre ereditano da una classe astratta ApplicationWindow. Questa classe astratta viene notificata ogni volta che il DataContext viene modificato e nel gestore controlla se DataContext supporta IRequestCloseViewModel. Se questo è il caso, un gestore di eventi è impostato per chiudere la finestra quando viene attivato l'evento.

In alternativa, come ha detto Kent, è possibile utilizzare controller schermo che gestiscono questo meccanismo in una classe esterna.

+0

Ciao Jalfp, questo suona davvero fantastico, hai un esempio della classe astratta di cui ho bisogno per ereditare tutte le finestre? .. Se si dispone anche di un esempio di Irquestcloseviewmodel, sarebbe fantastico –

+0

Ho intenzione di inserire un articolo sul mio blog nelle prossime ore. Ti farò sapere non appena sarà online :-) – japf

+0

Eccolo: http://www.japf.fr/2009/09/how-to-close-a-view-from-a-viewmodel/ Spero che questo aiuto :) – japf

8

In genere si utilizza una sorta di controller/presentatore/servizio per attivare l'attivazione/disattivazione dello schermo. MVVM non è pensato per essere il Un modello per regolarli tutti. Dovrai combinarlo con altri modelli in qualsiasi applicazione non banale.

Detto questo, in alcune situazioni ha senso disporre di un modello di visualizzazione che gestisca il ciclo di vita dei modelli di visualizzazione figlio. Ad esempio, potresti avere un EditorViewModel che gestisce un insieme di modelli di visualizzazione figlio, uno per ogni documento che viene modificato. In tal caso, la semplice aggiunta/rimozione di/da questa raccolta può comportare l'attivazione/disattivazione della vista. Ma questo non suona come il tuo caso d'uso.

2

Vorrei utilizzare un ApplicationController che istanzia il LoginViewModel e mostra LoginView. Quando l'utente procede con la schermata di accesso, ApplicationController chiude LoginView e mostra MainView con il suo MainViewModel.

Come questo può essere fatto è mostrato nelle applicazioni di esempio del progetto WPF Application Framework (WAF).

4

È possibile eseguire un comando che si collega alla finestra e al termine della chiusura della finestra. Quindi puoi associare quel comando a una proprietà sul tuo modello di vista ed eseguire il comando quando vuoi chiudere la finestra.

+0

Bello e semplice. – Darren

22

Non so cosa framework MVVM che si sta utilizzando, ma la maggior parte contengono una sorta di soluzione di messaggistica/notifica che è facile si registrino le cose per i messaggi che vengono inviati. Non c'è motivo per cui immagino che la tua vista non possa registrare un messaggio come "CloseWindowsBoundTo" e il viewModel come mittente. Quindi, a tuo avviso, puoi semplicemente registrarti per quel messaggio e confrontare il tuo attuale datacontext con il mittente. Se corrispondono, chiudi la finestra.

Semplice, e mantiene la vista astratta dal tuo viewmodel.

qui sarebbe il mio approccio con toolkit MVVM-luce:

Nella ViewModel:

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

E nel Vista:

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

Mi chiedo, se può causare una perdita di memoria perché si passa un collegamento a un oggetto che si suppone essere smaltito? .. –

2

Questa risposta mostra un altro modo per farlo :

How should the ViewModel close the form?

Utilizza una proprietà associata per associare la proprietà della finestra di DialogResult a una proprietà ViewModel. Quando si imposta il valore di DialogResult su true o false, la vista viene chiusa.

2

Basta chiudere in un EventHandler nel codice dietro e gestire tutto il resto nel modello di vista in cui è possibile utilizzare un bind del comando.

+0

Sto per essere colpito da un fulmine di Lightning a forma di ViewModel per fare questo, e non scrivere il mio Interfaccia IRequestCloseViewModel? – Ted

7

So che questa è una domanda vecchia, ma ho un bel modo di farlo, così ho pensato di condividere per chiunque altro inciampare in questo. Ho usato il comportamento allegato a dialogcloser, ma trovo la soluzione sottostante più semplice dove posso usarla. L'esempio riportato di seguito prende un esempio di un pulsante di chiusura sulla finestra per semplicità.

passare la finestra come parametro di comando.

nel pulsante XAML per la vista:

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

nel comando metodo eseguito nel modello di vista:

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

Per chiudere la vista dal viewmodel i utilizzata toolkit Galasoft MVVM Luce che è possibile scaricare qui: http://www.mvvmlight.net/

  1. creare una classe come questa: public class ClosingRequested: MessageBase {}

  2. aggiungere questo alla tua vista costruttore: Messenger.Default.Register (questo, vm, msg => Close());

  3. chiama questo per chiudere la finestra: Messenger.Default.Send (new ClosingRequested(), this);

0

È anche possibile farlo utilizzando l'evento.Anche se hai bisogno di 3 linee di codice nel tuo codice di visualizzazione (alcuni puristi di MVVM non amano questo);

Nel vostro ViewModel, si crea un evento che la vista può sottoscrivere:

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

Nella tua, vista si sottoscrive l'evento dopo che il metodo InitializeComponent come di seguito:

 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(); 
     } 

È semplicemente chiama RaiseClose() quando sei pronto per chiudere la View dal ViewModel.

È anche possibile utilizzare questo metodo per inviare un messaggio alla vista da viewmodel.

L'evento può essere inserito in un'interfaccia per evitare la dipendenza diretta della vista sul viewmodel.

Problemi correlati