6

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

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

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

我想要的是有某种 ApplicationViewModel 或 ApplicationController 像 Caliburn Conductor 一样工作,但不是在窗口内的视图之间切换,它应该在 LoginWindow 和 MainWindow 之间切换,并且还应该处理整个应用程序的关闭(其中还需要注销)。在激活时,它会显示 LoginWindow,处理 Login 事件,然后切换到主窗口(Shell)。如果用户选择“注销”,该事件应该再次冒泡到 ApplicationViewModel/Controller,这将停用/关闭 MainWindow,执行注销,然后再次显示 LoginDialog。类似的关闭事件会执行注销,然后关闭整个应用程序。

所以我的问题是:

  1. 你如何看待这个解决方案,你有另一个/更好的解决方案吗?
  2. 我该如何实施?;-)

非常感谢!

4

2 回答 2

19

我认为您的问题的解决方案相当容易。

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

首先创建一个接口 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适合您的控件或任何控件的操作。

下一步是覆盖OnStartupMethodBootstrapper 中的 。前提是您拥有一个实例WindowManager并由ShellViewModel您选择的 IoC 框架导出。

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当前窗口会通过调用TryClose. ShellViewModel同时,您可以通过将 设置为Application.ShutdownMode来防止应用程序被关闭OnExplicitShutdown。然后使用窗口管理器,通过将“登录”作为上下文信息传递给窗口管理器,以登录模式创建另一个窗口。这实际上是同一个 ViewModel,但是具有不同的视觉表示。

因为Logout你正在做同样的事情。

要使用 Caliburn 约定来完成这项工作,您需要一个特殊的项目结构,如此处所示(并在此处解释在此处输入图像描述

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

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

于 2012-08-17T21:02:04.053 回答
3

我已经尝试过创建一些基本上可以工作但可能需要更多工作才能真正可用的东西。完整的评论和来源可以在我网站上的这篇文章Caliburn.Micro 登录窗口示例中找到。

我使用IEventAggregatorCaliburn.Micro 来控制两个窗口之间的过渡。你得到这个代码来打开登录屏幕:

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);
于 2012-08-22T19:42:42.427 回答