我使用的是Caliburn Micro并且具有登录视图模型,该模型在启动时显示。
我正在使用一个单独的类来处理与服务器的所有连接,并为ViewModel提供简单的回调事件,这就是ITransportClient。
用户输入凭据,点击登录,对话框显示多个状态的连接过程(连接,验证用户名,下载配置)。在后台,Login ViewModel将调用ITransportClient.Login()
。
如果登录确定并且所有步骤都已完成,则表单应该关闭,主窗口ViewModel应该打开。如果凭据不正确或下载设置有问题,则应显示错误并保留登录表单。
如果服务器连接丢失(通过ITransportClient事件指示),则应用程序应尝试重新连接多次,如果服务器在可配置的时间段内保持脱机状态,则应再次显示登录窗口。
IWindowManager
只有ShowDialog
,ShowPopup
和ShowWindow
方法?我的引导程序:
public class SimpleInjectorBootstrapper : Caliburn.Micro.Bootstrapper
{
private Container container;
protected override void Configure()
{
this.container = new Container();
this.container.Register<IWindowManager, WindowManager>();
this.container.Register<IEventAggregator, EventAggregator>();
this.container.Register<IAppViewModel, AppViewModel>();
this.container.Register<ILoginViewModel, LoginViewModel>();
this.container.RegisterSingle<ITransportClient, Transport.WCF.TransportClient>();
}
protected override object GetInstance(Type serviceType, string key)
{
return this.container.GetInstance(serviceType);
}
protected override IEnumerable<object> GetAllInstances(Type serviceType)
{
return this.container.GetAllInstances(serviceType);
}
protected override void OnStartup(object sender, System.Windows.StartupEventArgs e)
{
base.OnStartup(sender, e);
var loginViewModel= this.container.GetInstance<ILoginViewModel>();
var windowManager = this.container.GetInstance<IWindowManager>();
windowManager.ShowWindow(loginViewModel);
}
}
我的LoginView模型如下:
public class LoginViewModel : PropertyChangedBase, ILoginViewModel
{
private readonly ITransportClient transportClient;
private readonly IWindowManager windowManager;
private string connectionStatus;
public LoginViewModel(ITransportClient transportClient, IWindowManager windowManager)
{
this.transportClient = transportClient;
this.windowManager = windowManager;
this.transportClient.ConnectionEvent += new TransportConnectionEventHandler(UpdateStatusHandler);
}
public void Login()
{
// set from view, to be done via property, implement later
var username = "test";
var password = "test";
var result = this.transportClient.Login(username, password);
// if result is ok, we should close our viewmodel, however we
// cant call IWindowManager.Close(this) as only show methods exist
// perhaps this is better handled elsewhere?
}
public void UpdateStatusHandler(string status)
{
this.ConnectionStatus = status;
}
public string ConnectionStatus
{
get
{
return this.connectionStatus;
}
set
{
this.connectionStatus = value;
NotifyOfPropertyChange(() => ConnectionStatus);
}
}
}
答案 0 :(得分:1)
CM使用IWindowManager
接口提供CM可以理解的窗口管理合同。实现本身是UI特定的东西 - 例如Telerik控件与Microsoft标准控件=不同。 IWindowManager
在CM中实现为WindowManager
,此管理器包含一个名为WindowConductor
的子类,其作用是处理来自Window
控件本身的事件并将调用传递给窗口(它是viewmodel和views容器之间的粘合剂)
看看:
此指挥为您管理窗口 - 如果查看实现,您可以看到它检查是否存在某些接口,例如IActivate
,IDeactivate
和IGuardClose
。如果您实现这些接口,您的窗口将获得更多生命周期功能。
继承Screen
而不是PropertyChangedBase
是免费获得这些接口实现的一种方法,您还可以获得IViewAware
的实现,它提供了自动视图缓存和一个有用的方法来获取参考视图
从此类继承或实现接口后,您可以调用方法通过VM关闭窗口(例如TryClose
)。 WindowConductor
将负责将必要的调用传递给窗口控件,甚至可以使用允许您取消关闭操作的IGuardClose
接口阻止窗口关闭。
我假设您已经在CM中拥有Actions
句柄,因为您似乎在VM上有登录方法。
现在这是一个答案中的问题 - 你需要进入弹出窗口路线吗?您可以继承Conductor<T>.Collections.OneActive
并致电ActivateItem(yourViewModel)
(T
可以是IScreen
)。激活新项目时,您的登录视图模型将自动停用,或者您可以打开登录失败的视图模型或类似的东西。虽然这不使用单独的窗口,但实现非常简单,只需在导体视图模型上绑定ContentControl
到ActiveItem
请查看详细信息(查看简单MDI部分及其周围):