2009-09-27 22 views
46

¿Alguien se encuentra con una forma ingeniosa de cerrar una vista en un modelo de vista usando MVVM?WPF (MVVM): ¿Cerrar una vista desde Viewmodel?

¿Tal vez hay una forma de usar el enlace para señalar la vista (ventana) para cerrar?

Realmente agradecería cualquier aporte que alguien tenga.

Básicamente tengo un loginView que está vinculado a un loginViewModel, en el viewmodel (usando el enlace en un comando) pruebo para ver si el inicio de sesión es exitoso y si lo es, básicamente cargo una nueva vista (mainview) y adjuntar su DataContext ...

pero todavía tengo la LoginView muestra - por eso es necesario señalar que para descargar ..

también esperaba para una solución genérica, porque estoy seguro de que voy a necesitar para hacer este tipo de cosas en otras situaciones

¿Alguna idea?

Respuesta

35

Editar: Ver my blog post para una explicación más detallada.

Cuando necesito lograr eso, utilizo una interfaz IRequestCloseViewModel que he creado.

Esta interfaz contiene solo un evento: RequestClose. Este evento lo plantea ViewModel (que hereda de una clase ViewModelBase Y implementa IRequestCloseViewModel) cuando quiere cerrar su vista asociada.

En mi aplicación, todas las ventanas heredan de una clase abstracta ApplicationWindow. Esta clase abstracta se notifica cada vez que se cambia el DataContext y en el controlador se comprueba si DataContext es compatible con IRequestCloseViewModel. Si este es el caso, un controlador de eventos se configura para cerrar la ventana cuando se dispara el evento.

Alternativamente, como dijo Kent, puede usar el controlador de pantalla que maneja este mecanismo en una clase externa.

+0

Hola Jalfp, esto suena muy bien, ¿Tienes un ejemplo de la clase abstracta de la que necesito heredar todas las ventanas? .. Si tienes un ejemplo que incluye Irquestcloseviewmodel también - sería genial –

+0

Voy a poner un artículo en mi blog en las próximas horas. Te lo haré saber tan pronto como esté en línea :-) – japf

+0

Aquí está: http://www.japf.fr/2009/09/how-to-close-a-view-from-a-viewmodel/ Espero que esta ayuda :) – japf

8

En general, utilizaría algún tipo de controlador/presentador/servicio para activar/desactivar la pantalla. MVVM no está destinado a ser el One Pattern to Rule Them All. Tendrá que combinarlo con otros patrones en cualquier aplicación no trivial.

Dicho esto, en algunas situaciones, tiene sentido tener un modelo de vista que administre el ciclo de vida de los modelos de vista infantil. Por ejemplo, puede tener un EditorViewModel que administre una colección de modelos de vista infantil, uno para cada documento que se edita. En ese caso, simplemente agregar/eliminar a/de esta colección puede hacer que la vista se active/desactive. Pero esto no parece que se ajuste a su caso de uso.

2

Yo usaría un ApplicationController que crea una instancia del LoginViewModel y muestra el LoginView. Cuando el usuario continúa con la pantalla de inicio de sesión, ApplicationController cierra el LoginView y muestra MainView con su MainViewModel.

Cómo se puede hacer esto se muestra en las aplicaciones de muestra del proyecto WPF Application Framework (WAF).

4

Puede hacer un comando que se adjunta a la ventana y cuando se ejecuta cierra la ventana. Luego puede vincular ese comando a una propiedad en su modelo de vista y ejecutar el comando cuando desee cerrar la ventana.

+0

Agradable y simple. – Darren

22

No está seguro de qué marco MVVM que está utilizando, pero la mayoría contienen algún tipo de solución de mensajería/notificación de que es fácil tienen cosas registran para los mensajes que se envían. No hay ninguna razón para que me imagine que su vista no podría registrarse para un mensaje como "CloseWindowsBoundTo" y viewModel como el remitente. Luego, en su opinión, puede simplemente registrarse para ese mensaje y comparar su actual contexto de datos con el remitente. Si coinciden, cierra la ventana.

Simple, y mantiene su vista abstraída de su modelo de vista.

Aquí sería mi enfoque usando kit de herramientas MVVM luz:

En el modelo de vista:

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

Y en la vista:

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

Solo me pregunto, si puede causar una pérdida de memoria porque pasas un enlace a un objeto que se suponía que iba a ser eliminado ... –

2

Esta respuesta muestra otra manera de hacer esto :

How should the ViewModel close the form?

Utiliza una propiedad adjunta para vincular la propiedad de la ventana DialogResult a una propiedad ViewModel. Al establecer el valor de DialogResult en verdadero o falso, la vista se cierra.

2

Simplemente cierre en un manejador de eventos en el código subyacente y maneje todo lo demás en el modelo de vista donde puede usar un enlace de comando.

+0

Voy a recibir un rayo con forma de ViewModel al hacerlo y no escribir el mío Interfaz IRequestCloseViewModel? – Ted

7

Sé que esta es una pregunta antigua, pero tengo una buena manera de hacerlo, así que pensé en compartirla con cualquier persona que tropezara con esto. Solía ​​usar el comportamiento adjunto de diálogo más cercano, pero encuentro la solución a continuación más fácil donde puedo usarlo. El ejemplo siguiente toma un ejemplo de un botón de cierre en la ventana para simplificar.

pase la ventana como el parámetro de comando.

en el xaml botón para la vista:

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

en el comando ejecutar el método en el modelo de vista:

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

para cerrar la vista de modelo de vista He utilizado el kit de herramientas de Galasoft MVVM Light cuales usted puede descargar aquí: http://www.mvvmlight.net/

  1. crear una clase como esta: clase pública ClosingRequested: MessageBase {}

  2. Agregar a su vista constructor: Messenger.Default.Register (esto, vm, msg => Close());

  3. llama esto para cerrar tu ventana: Messenger.Default.Send (nuevo ClosingRequested(), this);

0

También puede hacerlo mediante el evento.Aunque necesitas como 3 líneas de códigos en tu código de vista atrás (a algunos puristas MVVM no les gusta esto);

En su modelo de vista, se crea un evento que la vista se puede suscribir a:

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

En su, vista en la que se suscribe al evento después de que su método InitializeComponent de la siguiente manera:

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

Usted simplemente llame a RaiseClose() cuando esté listo para cerrar la Vista desde el ViewModel.

Incluso puede utilizar este método para enviar mensajes a la vista desde el modelo de vista.

El evento se puede poner en una interfaz para evitar la dependencia directa de la vista en el modelo de vista.

Cuestiones relacionadas