WPF(MVVM): ¿Cerrar una vista desde Viewmodel?
wpftoolkit (11)
¿Alguien se encuentra con una forma ingeniosa de cerrar una vista en un modelo de vista usando MVVM?
¿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 adjunto su datacontext. ..
pero todavía tengo el loginView mostrado, así que necesito señalizarlo para descargar ...
También esperaba una solución genérica porque estoy seguro de que tendré que hacer este tipo de cosas en otras situaciones
¿Algunas ideas?
En general, utilizaría algún tipo de controlador / presentador / servicio para controlar la activación / desactivación de la pantalla. MVVM no pretende ser el único patrón para gobernarlos a todos . 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.
Esta respuesta muestra otra forma de hacer esto:
¿Cómo debería ViewModel cerrar el formulario?
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.
No estoy seguro de qué marco de MVVM está utilizando, pero la mayoría contiene algún tipo de solución de mensajería / notificación que es fácil que las cosas se registren 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í estaría mi enfoque usando el juego de herramientas MVVM-light:
En ViewModel:
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();
}
});
Para cerrar la vista desde el modelo de vista, utilicé el Galasoft MVVM Light Toolkit, que puede descargar aquí: http://www.mvvmlight.net/
crea una clase como esta: public class ClosingRequested: MessageBase {}
agregue esto a su vista constructor: Messenger.Default.Register (this, vm, msg => Close ());
llama esto para cerrar tu ventana: Messenger.Default.Send (nuevo ClosingRequested (), this);
Puede hacer un comando que se conecta 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.
Sé que esta es una vieja pregunta, 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.
pasar la ventana como el parámetro de comando.
en el botón xaml para la vista:
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
en el comando ejecutar método en el modelo de vista:
if (parameter is System.Windows.Window)
{
(parameter as System.Windows.Window).Close();
}
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.
También puedes hacer esto usando 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 viewmodel, crea un evento al que la vista puede suscribirse:
public event CloseEventHandler Closing;
public delegate void CloseEventHandler();
private void RaiseClose()
{
if (Closing != null)
Closing();
}
En su vista, puede suscribirse al evento después de 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();
}
Simplemente llame a RaiseClose () cuando esté listo para cerrar la Vista desde el ViewModel.
Incluso puede usar este método para enviar un mensaje 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.
Yo usaría un ApplicationController que crea una instancia de 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) .
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>
Editar: mira mi blog para una explicación más detallada.
Cuando necesito lograr eso, uso 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 un controlador de pantalla que maneje este mecanismo en una clase externa.