2012-08-15 21 views
6

Soy nuevo en Caliburn.Micro y me pregunto cuál es la mejor manera de manejar los ciclos de inicio de sesión/cierre de sesión de usuario en mi aplicación. Vi algunas sugerencias en línea para implementar esto usando una Vista de Shell vacía que cambia entre el LoginView y la vista principal de la aplicación, cada una con un ViewModel personalizado, por supuesto.¿Cómo manejo el inicio/cierre de sesión en Caliburn.Micro?

Realmente no me gusta esta solución, porque para mí son 2 ventanas separadas con propiedades muy diferentes (Título, Icono, Tamaño) y parece una solución sucia dos cambiar una ventana para parecerse a la otra. Otro problema es que la ventana de inicio de sesión proviene de una biblioteca de utilidades que no controlo y que no utiliza Caliburn.Micro, es una ventana antigua que me da un evento cuando el usuario hace clic en "Iniciar sesión".

También vi sugerencias para mostrar este cuadro de diálogo en el método de arranque Bootstrapper, pero el problema que veo es que el usuario puede elegir "Cerrar sesión" de la aplicación que debería mostrar el cuadro de diálogo Iniciar sesión nuevamente. Me parece incorrecto manejar el cambio entre las Vistas en el Bootstrapper.

Lo que me gustaría es tener algún tipo de ApplicationViewModel o ApplicationController que funcione como un Caliburn Conductor, pero en lugar de cambiar entre Views dentro de una ventana, debe cambiar entre LoginWindow y MainWindow y también debe manejar el cierre de la toda la aplicación (que también requiere un cierre de sesión). En Activación, mostraría la ventana de inicio de sesión, manejaría el evento de inicio de sesión y luego cambiaría a la ventana principal (Shell). Si el usuario elige "LogOut", el evento volverá a aparecer en el ApplicationViewModel/Controller, que desactivaría/cerraría MainWindow, realizaría Logout y luego volvería a mostrar el LoginDialog. Un evento Similar cerraría el cierre de sesión, pero luego cerrará toda la aplicación.

Así que mis preguntas son:

  1. ¿Qué piensa acerca de esta solución y tienes otra/mejor?
  2. ¿Cómo implemento esto? ;-)

¡Muchas gracias!

+0

Cuando dice "ventana viejo y simple" hacer ¿WPF o WinForms? ¿La ventana de inicio de sesión también hace el trabajo real de autenticar a un usuario o tendría que manejar el evento "Iniciar sesión" y hacer eso? – Kioshiki

+1

ventana de WPF y genera un evento de inicio de sesión que administro utilizando un servicio de autenticación que obtengo de mi contenedor de IoC. – aKzenT

Respuesta

16

Creo que la solución a su problema es bastante fácil.

En pocas palabras, está creando un ViewModel como Shell que se representa con una ventana de inicio de sesión cuando se inicia la aplicación. Si el usuario inicia sesión con éxito, esta ventana se cierra y se muestra la misma instancia de viewModel en una ventana de contenido. Si el usuario está cerrando sesión, la ventana de inicio de sesión se muestra nuevamente.

En primer lugar crear un iShell interfaz que expone dos delegados LoginSuccessful y Logout

public interface IShell 
    { 
     Action LoginSuccessful { get; set; } 
     Action Logout { get; set; } 
    } 

Siguiente crear una clase ShellViewModel que implementa IShell

public class ShellViewModel : Screen, IShell 
    { 
     public ShellViewModel() 
     { 
      LoginSuccessful = delegate { }; 
      Logout = delegate { }; 
     } 

     public Action LoginSuccessful { get; set; } 
     public Action Logout { get; set; } 

     public void DoLogin() 
     { 
      LoginSuccessful(); 
     } 

     public void DoLogout() 
     { 
      Logout(); 
     } 
    } 

Los métodos DoLogin y DoLogout son acciones que pueden ser vinculado a un Button o cualquier control apropiado para usted.

El siguiente paso es anular el OnStartupMethod en su Bootstrapper. Esta premisa tiene una instancia de WindowManager y ShellViewModel exportada por un Marco de IoC de su elección.

protected override void OnStartup(object sender, StartupEventArgs e) 
     { 
      var windowManager = IoC.Get<IWindowManager>(); 
      var viewModel = IoC.Get<IShell>(); 

      viewModel.LoginSuccessful = 
       () => GuardCloseAndReopen("Content"); 

      viewModel.Logout = 
       () => GuardCloseAndReopen("Login"); 

      windowManager.ShowWindow(viewModel, "Login"); 
     } 

     private void GuardCloseAndReopen(string shellViewMode) 
     { 
      var windowManager = IoC.Get<IWindowManager>(); 
      var shellScreen = IoC.Get<IShell>() as Screen; 

      Application.ShutdownMode = ShutdownMode.OnExplicitShutdown; 

      shellScreen.TryClose(); 

      Application.ShutdownMode = ShutdownMode.OnLastWindowClose; 

      windowManager.ShowWindow(shellScreen, shellViewMode); 
     } 

El truco para esto es: Si se llama al método DoLogout, la ventana actual se cierra llamando TryClose en el ShellViewModel. Al mismo tiempo, evita que la aplicación se cierre configurando Application.ShutdownMode en OnExplicitShutdown. Luego, usando el administrador de ventanas, crea otra ventana en el Modo de inicio de sesión al pasar "Iniciar sesión" como información de contexto a windowManager. Sin embargo, este es el mismo ViewModel con una representación visual diferente.

Para Logout usted está haciendo lo mismo a su alrededor.

Para conseguir este trabajo mediante convenios Caliburn, se necesita una estructura de proyecto especial, como se ve aquí (y explicó there): enter image description here

Ahora te reto a asumir este código y crear una pequeña aplicación de ejemplo. Cree una vista Login (que inicia sesión con un botón o lo que sea) y cree una vista Content con un botón Cerrar sesión utilizando los métodos LoginSuccessful/Logout.

Esto resolverá su problema con un mínimo de Código y clases. Espero que esto sea útil para ti.

+0

Estoy interesado en cómo esto también funcionaría. En su ejemplo, ¿qué es ShellViewMode? ¿Debería ser ShellViewModel o tal vez solo una cadena? También aKzenT declaró que la ventana de inicio de sesión ya existía, ¿cómo podría afectar esto su diseño? – Kioshiki

+0

ShellViewMode era un error tipográfico. Por supuesto, esta es una cadena que pasa la información de contexto al administrador de ventanas. También podría establecer este contexto en una enumeración, lo que sería una buena idea. Para la ventana de inicio de sesión existente, coloque esta xaml en Login.xaml y configure la interfaz de usuario para las acciones existentes en viewModel. Esto puede no ser tan complejo porque la mayoría de las veces los cuadros de diálogo de inicio de sesión son simplemente un botón de inicio de sesión/cancelación con cajas de texto de nombre de usuario/contraseña. Autorisation puede ser hecho por el ShellViewModel o extender la interfaz con algún delegado de validación para desacoplar esta lógica y hacerla cambiable durante el tiempo de ejecución. –

+1

Pensé que una cuerda era correcta en este caso, como dices una enumeración sería mejor. Creo que todavía no tienes la misma idea que yo con la ventana de inicio de sesión existente (aunque tal vez tenga una idea equivocada).Estoy pensando en una situación donde tienes que usar una ventana existente de un ensamblaje binario, tal vez en una empresa tienen una ventana WPF o incluso un formulario WindowsForms que se debe usar para el proceso de inicio de sesión que expone eventos, etc. (podría deberse a a la validación, etc.) Creo que eso haría bastante difícil encontrar una solución limpia. – Kioshiki

3

He intentado crear algo que básicamente funciona, pero que probablemente necesite un poco más de trabajo para ser realmente útil. Los comentarios completos y la fuente se pueden encontrar en esta publicación Caliburn.Micro Login Window sample en mi sitio web.

Utilicé el IEventAggregator de Caliburn.Micro para controlar la transición entre las dos ventanas. Se obtiene el código para abrir la pantalla de inicio de sesión: se utiliza

public void Handle(LoginEvent message) 
{ 
    LoginWindow loginWindow = new LoginWindow(); 
    loginWindow.Login += new EventHandler<LoginEventArgs>(this.LoginWindow_Login); 
    loginWindow.Cancel += new EventHandler(LoginWindow_Cancel); 
    loginWindow.ShowDialog(); 
} 

esta misma fuente, tanto para la primera vez que la aplicación se abre y cuando el evento se publica Salir. el evento Salir ve así:

public void Handle(LogoutEvent message) 
{ 
    Application.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown; 
    message.Source.TryClose(); 
    Application.Current.ShutdownMode = ShutdownMode.OnLastWindowClose; 
    this.events.Publish(new LoginEvent()); 
} 

Cuando un inicio de sesión tiene éxito, utiliza este código para abrir la ventana principal que se basa en un modelo de vista:

ContentViewModel viewModel; 
viewModel = IoC.Get<ContentViewModel>(); 
viewModel.Username = e.Username; 
this.windowManager.ShowWindow(viewModel); 
Cuestiones relacionadas