首页 > 解决方案 > WPF MVVM 中 ViewModel 上的 Mediatr 通知

问题描述

在实现 WPF 应用程序时,我偶然发现了我的应用程序在每个 ViewModel 中都需要一些全局数据的问题。然而,一些 ViewModel 只需要读取权限,而其他的需要对该字段的读/写权限。起初,我偶然发现了 Microsoft 的 SessionContext 理念,如下所示:

public class SessionContext
    {
        #region Public Members
        public static string UserName { get; set; }
        public static string Role { get; set; }

        public static Teacher CurrentTeacher { get; set; }
        public static Parent CurrentParent { get; set; }
        public static LocalStudent CurrentStudent { get; set; }

        public static List<LocalGrade> CurrentGrades { get; set; }
        #endregion

        #region Public Methods
        public static void Logon(string userName, string role)
        {
            UserName = userName;
            Role = role;
        }

        public static void Logoff()
        {
            UserName = "";
            Role = "";
            CurrentStudent = null;
            CurrentTeacher = null;
            CurrentParent = null;
        }
        #endregion
}

这不是(至少在我看来)可以很好地测试,并且如果我的全局数据增长它会出现问题(认为这可能发生在这个应用程序中)。我发现的下一件事是来自此链接的中介者/中介者模式的实现。我喜欢设计的理念 Norbert 会来到这里,并考虑为我的项目实施类似的东西。然而,在这个项目中,我已经在使用令人印象深刻的 Mediatr Nuget 包,这也是一个 Mediator 实现。所以我想“为什么要重新发明轮子”,如果我可以使用一个很好且经过良好测试的调解器。但这里开始了我真正的问题:如果其他 ViewModel 对全局数据的更改发送到我的只读 ViewModel,我会使用通知。这意味着:

public class ReadOnlyViewModel : NotificationHandler<Notification>
{
   //some Member

    //global Data
    public string Username {get; private set;}

    public async Task Handle(Notification notification, CancellationToken     token) 
    {
        Username = notification.Username;
    }

}

现在的问题: 1. 这是使用 MVVM 的好习惯吗(只是感觉这样做是错误的,因为感觉就像在 ViewModel 中暴露业务逻辑) 2. 有没有更好的方法来分离它,以便我的 Viewmodel 不需要继承 5 到 6 个不同的 NotificationHandlers<,>?

更新: 澄清我想在这里实现的目标:我的目标是实现一个 wpf 应用程序,该应用程序为其一个窗口管理一些全局数据(比如上面提到的用户名)。这意味着因为我使用的是 DI 容器(并且因为它是什么类型的数据),所以我必须将提议的 Service @mm8 声明为单例。但是,如果(我有这种情况)我需要打开一个此时需要不同全局数据的新窗口,这有点问题。这意味着我要么需要将生命周期更改为“某种范围”之类的东西,要么(打破类的单一职责)为不同的目的添加更多字段,或者我为我可能需要的 n 个可能的 Windows 创建 n 个服务打开。对于拆分服务的第一个想法:

标签: c#wpfmvvmmediatr

解决方案


您可以使用注入视图模型的共享服务。例如,它可以实现两个接口,一个用于写操作,一个用于只读操作,例如:

public interface IReadDataService
{
    object Read();
}

public interface IWriteDataService : IReadDataService
{
    void Write();
}

public class GlobalDataService : IReadDataService, IWriteDataService
{
    public object Read()
    {
        throw new NotImplementedException();
    }

    public void Write()
    {
        throw new NotImplementedException();
    }
}

然后,您将注入应该具有写访问权限的视图模型 a IWriteDataService(以及其他具有 a 的IReadDataService):

public ViewModel(IWriteDataService dataService) { ... }

该解决方案既使代码易于理解又易于测试。


推荐阅读