2012-08-15 33 views
6

我是Caliburn.Micro的新手,我想知道在我的应用程序中处理用户登录/注销周期的最佳方式是什么。我在网上看到了一些建议,使用空的Shell-View在LoginView和主应用程序视图之间切换,当然每个视图都有一个自定义ViewModel。如何处理Caliburn.Micro中的登录/注销?

我不太喜欢这个解决方案,因为对于我来说,这些是2个独立的窗口,具有非常不同的属性(标题,图标,大小),它似乎是一个不洁的解决方案,两个窗口看起来像另一个。另一个问题是,登录窗口来自一个实用程序库,我不控制它,不使用Caliburn.Micro,它是一个普通的旧窗口,当用户单击“登录”时,它会给我一个事件。

我还看到了在Bootstrapper启动方法中显示此对话框的建议,但是我看到的问题是用户可以选择“注销”应用程序,该应用程序应该再次显示“登录”对话框。我在引导程序中处理视图之间的切换似乎是错误的。

我想要的是某种类似于Caliburn Conductor的ApplicationViewModel或ApplicationController,但不是在窗口内的视图之间切换,它应该在LoginWindow和MainWindow之间切换,并且还应该处理关闭整个应用程序(也需要注销)。在激活时,它将显示LoginWindow,处理登录事件,然后切换到主窗口(Shell)。如果用户选择“LogOut”,事件应该再次启动到ApplicationViewModel/Controller,它将关闭/关闭MainWindow,执行注销,然后再次显示LoginDialog。类似的关闭事件将执行注销,但然后关闭整个应用程序。

所以我的问题是:

  1. 你觉得这个怎么样的解决方案,做您有其它/更好的?
  2. 我该如何实施? ;-)

非常感谢!

+0

你是WPF还是WinForms?登录窗口还会执行验证用户的实际工作,还是您必须处理“登录”事件并执行此操作? – Kioshiki 2012-08-20 17:15:23

+1

WPF窗口,它引发了一个登录事件,我使用从IoC容器获得的身份验证服务处理该事件。 – aKzenT 2012-08-20 21:09:43

回答

16

我认为解决您的问题相当简单。

简而言之,您将创建一个ViewModel作为Shell,并在应用程序启动时使用登录窗口表示。如果用户成功登录,则此窗口关闭,并且在内容窗口中显示相同的viewModel实例。如果用户正在注销,则会再次显示登录窗口。

首先创建一个接口IShell的暴露两位代表LoginSuccessfulLogout

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

接着创建一个类ShellViewModel它实现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(); 
     } 
    } 

方法DoLoginDoLogout是操作其可以是绑定到Button或任何适合您的控制。

下一步是重写引导程序中的​​。此处所包含您所选IoC框架导出的WindowManagerShellViewModel的实例。

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

诀窍是这样的:如果DoLogout方法被调用,当前窗口被通过在ShellViewModel调用TryClose关闭。同时,通过将Application.ShutdownMode设置为OnExplicitShutdown,可以防止应用程序被关闭。然后使用窗口管理器,通过将“登录”作为上下文信息传递给windowManager,以登录模式创建另一个窗口。这实际上是相同的ViewModel,但是,具有不同的视觉表示。

对于Logout你正在做同样的事情。

为了得到这个使用卡利约定的工作,你需要为这里看到一个特殊的项目结构(并解释there): enter image description here

现在我挑战你利用这个代码,并创建一个小示例应用程序。创建Login视图(使用按钮或其他方式进行登录),并使用LoginSuccessful/Logout方法创建带有注销按钮的Content视图。

这将以最少的代码和类来解决您的问题。希望这会对你有所帮助。

+0

我很感兴趣,这也是如此。在你的例子中,ShellViewMode是什么?它应该是ShellViewModel还是只是一个字符串?另外aKzenT说登录窗口已经存在,那么这会如何影响你的设计呢? – Kioshiki 2012-08-18 19:00:54

+0

ShellViewMode是一个错字。当然,这是一个将上下文信息传递给窗口管理器的字符串。您也可以将此上下文设置为枚举,这将是一个好主意。 对于现有的登录窗口,将此xaml放入Login.xaml,并将UI设置为viewModel中现有的Actions。这可能不那么复杂,因为大多数时候,登录对话框只是一个带有用户名/密码文本框的登录/取消按钮。然后可以通过ShellViewModel完成Autorisation,或者使用某个验证代理扩展接口以解耦此逻辑,并使其在运行时变为可变。 – 2012-08-19 13:33:52

+1

我认为在这种情况下字符串是正确的,因为你说一个枚举会更好。我认为你现在的登录窗口仍然没有和我一样的想法(尽管我可能有错误的想法)。我正在考虑一种情况,您必须使用二进制程序集中的现有窗口,可能是在拥有WPF窗口的公司中,或者甚至是必须用于公开事件等登录过程的WindowsForms窗体(可能是由于验证等)。我认为这很难找到一个干净的解决方案。 – Kioshiki 2012-08-19 13:57:39

3

我已经开始创建基本上可行的东西,但可能需要更多的工作才能真正实用。完整的评论和来源可以在我的网站上找到这个职位Caliburn.Micro Login Window sample

我使用Caliburn.Micro的IEventAggregator来控制两个窗口之间的转换。你得到这个代码来打开登录界面:

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

此相同的源用于两个第一次打开应用程序并在注销事件发布。注销事件看起来是这样的:

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

当登录成功,它使用此代码来打开它是基于一个ViewModel主窗口:当你说“普通老式窗”做

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