1

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

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

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

  1. 启动和初始化应用程序。
  2. 显示登录表单。
  3. 登录表单执行与聊天服务器的连接ITransportClient.Login(username, password)
  4. 如果登录成功,则显示一个新的 MainWindow 视图,如果登录失败,则再次提示用户输入凭据。
  5. 登录后,MainWindow 控制发送和接收到 WCF 服务的消息。
  6. 当与服务器失去连接时(由 通知ITransportClientCallback.OnTransportDisconnected),或者当用户单击注销时,登录表单会再次显示。

凭借我现有的技术,这是我的第一个 MVVM 项目,我有以下架构和设计问题:

  1. 我应该使用什么设计模式来控制显示单独的登录屏幕,然后在连接时显示主屏幕,并在连接丢失时恢复到登录屏幕?
  2. 谁应该控制聊天应用程序的连接状态,这段代码应该放在哪里?这个状态会属于引导程序类吗?
  3. 我是否可以将 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);
    }
}
4

1 回答 1

3

我应该使用什么设计模式来控制显示单独的登录屏幕,然后在连接时显示主屏幕,并在连接丢失时恢复到登录屏幕?

在很多情况下,MVVM 项目伴随着一个“中介”或“信使”。所有的 View Model 都可以通过这种机制,通过订阅和发布消息的方式相互交互。所有虚拟机都会订阅“UserLoggedOutMessage”并做出必要的响应(即将其视觉状态更改为只读,或者根本不显示任何内容)。单独的引导程序还可以将用户“重定向”到登录屏幕。

谁应该控制聊天应用程序的连接状态,这段代码应该放在哪里?这个状态会属于引导程序类吗?

一种方法是对应用程序的状态进行抽象 - 这等效于 asp.net 中的 HTTPContext.Current 变量。你可以有一个 Session 对象,它有一个 CurrentState 只读属性,对应的 Login()、Logout()、SendMessage() 方法充当状态机。一旦应用程序的状态发生变化,所有视图模型都会订阅事件 - 再次通过中介。Session 对象可以是引导程序上的静态变量,也可以是通过 IoC 注入到所有 VM 的单例。

我是否可以将 ITransportClient 注册为持久性实例范围,并在需要时通过注入需要它的 ViewModel 来控制多个表单(即登录表单和主窗口表单)?

这绝对是这个想法。在大多数 MVVM 项目中,您可能希望将依赖项的单个实例注入到 VM 中。这允许更有效的内存使用,还允许一个干净的面向对象模型(与过程不可变事务脚本相反)。

话虽如此,如果这是尝试检查“应用程序状态”,我会将抽象级别更改为更高的级别,例如 IApplicationStateMachine 或 IUserSession。这样,如果您想在一个应用程序实例中支持多个用户,理论上您可以拥有多个 IUserSession 对象实例。

于 2012-11-25T11:56:46.940 回答