具有自包含客户机-服务器代码和IoC容器的有状态MVVM应用程序体系结构

具有自包含客户机-服务器代码和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连接聊天服务器。登录(用户名、密码) 如果登录成功,则显示新的主窗口视图;如果登录失败,则再次提示用户输入凭据 登录时,主窗

我有一个应用程序,它有多个屏幕并与WCF web服务对话。我将SimpleInjector用于我最喜欢的IoC容器,Caliburn Micro用于带有WPF的MMVM

我有一个单独的类实现
ITransportClient
,它控制到web服务的连接,并发送和接收消息

该应用程序具有以下状态:

  • 应用程序的启动和初始化
  • 显示登录表单
  • 登录表单使用ITransportClient连接聊天服务器。登录(用户名、密码)
  • 如果登录成功,则显示新的主窗口视图;如果登录失败,则再次提示用户输入凭据
  • 登录时,主窗口控制发送和接收到WCF服务的消息
  • 当与服务器的连接断开时(由
    ITransportClientCallback.OnTransportDisconnected
    通知),或当用户单击注销时,将再次显示登录表单
  • 利用我现有的技术,这是我的第一个MVVM项目,我有以下架构和设计问题:

  • 我应该使用什么设计模式来控制显示一个单独的登录屏幕,然后在连接时显示主屏幕,并在连接断开时恢复到登录屏幕
  • 谁应该控制聊天应用程序的连接状态以及该代码的位置?这个州会在引导程序类中吗
  • 我是否可以将ITransportClient注册为持久性实例范围,并在需要时通过注入需要它的ViewModel(即登录表单和主窗口表单)进行多表单控制
  • 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中执行操作,那么它将违反开闭原则。