具有自包含客户机-服务器代码和IoC容器的有状态MVVM应用程序体系结构
我有一个应用程序,它有多个屏幕并与WCF web服务对话。我将SimpleInjector用于我最喜欢的IoC容器,Caliburn Micro用于带有WPF的MMVM 我有一个单独的类实现具有自包含客户机-服务器代码和IoC容器的有状态MVVM应用程序体系结构,mvvm,architecture,caliburn.micro,simple-injector,Mvvm,Architecture,Caliburn.micro,Simple Injector,我有一个应用程序,它有多个屏幕并与WCF web服务对话。我将SimpleInjector用于我最喜欢的IoC容器,Caliburn Micro用于带有WPF的MMVM 我有一个单独的类实现ITransportClient,它控制到web服务的连接,并发送和接收消息 该应用程序具有以下状态: 应用程序的启动和初始化 显示登录表单 登录表单使用ITransportClient连接聊天服务器。登录(用户名、密码) 如果登录成功,则显示新的主窗口视图;如果登录失败,则再次提示用户输入凭据 登录时,主窗
ITransportClient
,它控制到web服务的连接,并发送和接收消息
该应用程序具有以下状态:
ITransportClientCallback.OnTransportDisconnected
通知),或当用户单击注销时,将再次显示登录表单ITransportClient
界面如下:
public interface ITransportClientCallback
{
string OnReceivedMessage();
void OnTransportDisconnected();
}
// transport interface that client calls
public interface ITransportClient
{
bool SendLogin(string username, string password);
void SendLogout();
void SendMessage();
void RegisterCallback(ITransportClientCallback applicationHostCallback);
}
以及使用SimpleInjector的Caliburn.Micro引导程序代码:
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.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 appViewModel = this.container.GetInstance<IAppViewModel>();
var windowManager = this.container.GetInstance<IWindowManager>();
windowManager.ShowWindow(appViewModel);
}
}
公共类SimpleInjectorBootstrapper:Caliburn.Micro.Bootstrapper
{
私人货柜;
受保护的覆盖无效配置()
{
this.container=新容器();
this.container.Register();
this.container.Register();
this.container.Register();
this.container.RegisterSingle();
}
受保护的覆盖对象GetInstance(类型serviceType,字符串键)
{
返回此.container.GetInstance(serviceType);
}
受保护的重写IEnumerable GetAllInstances(类型serviceType)
{
返回此.container.GetAllInstances(serviceType);
}
启动时受保护的覆盖无效(对象发送方,System.Windows.StartupEventArgs e)
{
启动时(发送方,e);
var appViewModel=this.container.GetInstance();
var windowManager=this.container.GetInstance();
windowManager.ShowWindow(appViewModel);
}
}
我应该使用什么设计模式来控制显示单独的登录
屏幕,然后连接主屏幕,并返回到
连接断开时的登录屏幕
在很多情况下,MVVM项目都伴随着“调解人”或“信使”。通过订阅和发布消息,所有视图模型都可以通过这种机制相互交互。所有虚拟机都将订阅“UserLoggedOutMessage”,并执行必要的响应(即将其可视状态更改为只读,或根本不显示任何内容)。单独的引导程序还可以将用户“重定向”到登录屏幕
谁应该控制聊天应用程序的连接状态
这个代码会放在哪里?这个州会成为引导者吗
上课
一种方法是对应用程序的状态进行抽象-这相当于asp.net中的HTTPContext.Current变量。您可以有一个会话对象,该对象具有CurrentState只读属性和相应的Login()、Logout()、SendMessage()方法,这些方法充当状态机。然后,当应用程序的状态发生变化时,所有视图模型都会订阅这些事件——同样是通过中介。会话对象可以是引导程序上的静态变量,也可以是通过IoC注入所有VM的单例
我可以将ITransportClient注册为持久性实例吗
范围,并在需要时具有多个窗体控件
到需要它的ViewModel(即登录表单和
主窗口(表格)
这绝对是个好主意。在大多数MVVM项目中,您希望将依赖项的单个实例注入到VM中。这允许更有效地使用内存,还允许使用干净的面向对象模型(与过程性不可变事务脚本相反)
话虽如此,如果这是为了检查“应用程序状态”,我会将抽象级别更改为更高的级别,例如iaapplicationstatemachine或IUserSession。这样,如果您想在一个应用程序实例中支持多个用户,理论上可以有多个IUserSession对象实例。谢谢Ronald,我们可以通过从ViewModel发送给处理程序的命令进一步抽象出职责,从而允许事务性命令和生命周期范围由每个命令请求管理。我读过cuttingedge.it/blogs/steven/pivot/entry.php?id=91,我觉得这非常适合这里,如果我们想添加事务支持,我们可以通过使用命令并将命令包装到适配器中来实现,而无需修改ViewModel。如果我们直接在ViewModel中执行操作,那么它将违反开闭原则。