我是Caliburn.Micro的新手,我想知道在我的应用程序中处理用户登录/注销周期的最佳方法是什么。我在网上看到了一些使用空Shell-View实现这一点的建议,它在LoginView和主应用程序视图之间切换,当然每个都有一个自定义ViewModel。
我真的不喜欢这个解决方案,因为对我来说这些是两个独立的窗口,具有非常不同的属性(标题,图标,大小),它似乎是一个不干净的解决方案,两个窗口改变一个看起来像另一个窗口。另一个问题是,登录窗口来自一个我无法控制但不使用Caliburn.Micro的实用程序库,它是一个普通的旧窗口,当用户单击“登录”时,它会给我一个事件。
我还看到了在Bootstrapper启动方法中显示此对话框的建议,但我看到的问题是用户可以选择应该“注销”应该再次显示“登录”对话框的应用程序。处理Bootstrapper中的Views之间的切换似乎是错误的。
我想要的是使用某种类似于Caliburn Conductor的ApplicationViewModel或ApplicationController,但不是在Window内的Views之间切换,它应该在LoginWindow和MainWindow之间切换,并且还应该处理整个Closing应用程序(也需要注销)。在激活时,它将显示LoginWindow,处理Login事件,然后切换到主窗口(Shell)。如果用户选择“LogOut”,则该事件应再次冒泡到ApplicationViewModel / Controller,这将停用/关闭MainWindow,执行Logout,然后再次显示LoginDialog。类似的关闭事件会执行注销,但随后关闭整个应用程序。
所以我的问题是:
非常感谢!
答案 0 :(得分:16)
我认为解决问题的方法相当简单。
简而言之,您正在创建一个ViewModel作为Shell,在应用程序启动时用登录窗口表示。如果用户成功登录,则关闭该窗口,并在内容窗口中显示相同的viewModel实例。如果用户正在注销,则会再次显示“登录窗口”。
首先创建一个接口IShell,公开两个代理LoginSuccessful
和Logout
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();
}
}
方法DoLogin
和DoLogout
是可以绑定到Button
或适合您的任何控件的操作。
下一步是覆盖Bootstrapper中的OnStartupMethod
。这样做的前提是您拥有由您选择的IoC框架导出的WindowManager
和ShellViewModel
的实例。
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
来阻止关闭应用程序。然后使用windowmanager,通过将“Login”作为Context信息传递给windowManager,在Login Mode中创建另一个窗口。这实际上是相同的ViewModel,但具有不同的可视化表示。
对于Logout
,你正在做同样的事情。
要使用Caliburn约定来实现此功能,您需要一个特殊的项目结构,如此处所示(并解释there):
现在我挑战你采取这个代码并创建一个小样本应用程序。创建一个Login
视图(使用Button或其他任何方式登录),并使用LoginSuccessful / Logout方法创建一个带有Logout按钮的Content
视图。
这将使用最少的代码和类来解决您的问题。希望这对你有所帮助。
答案 1 :(得分: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();
}
第一次打开应用程序和发布Logout事件时,会使用相同的源代码。 Logout事件如下所示:
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);