为 MVVM 用户控件和应用程序实现一个简单的 Messenger

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡/ 赠书活动

目前,正在 星球 内带小伙伴们做第一个项目:全栈前后端分离博客项目,采用技术栈 Spring Boot + Mybatis Plus + Vue 3.x + Vite 4手把手,前端 + 后端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,陪伴式直到项目上线,目前已更新了 204 小节,累计 32w+ 字,讲解图:1416 张,还在持续爆肝中,后续还会上新更多项目,目标是将 Java 领域典型的项目都整上,如秒杀系统、在线商城、IM 即时通讯、权限管理等等,已有 870+ 小伙伴加入,欢迎点击围观

用户控件很棒。您将一个易于使用(最好的情况下)的组件放在一起,以便在您的项目中重用。有时,您甚至将该控件放入(可移植的)类库中以使其跨平台可用。大多数用户控件都是在没有 MVVM 的情况下编写的,仅使用 DependencyProperties 和匹配的代码隐藏文件。

但是 – 可以创建一个带有自己的 ViewModel 的用户控件,只保留代码中的 DependencyProperties。对于由控件视图生成的值,存在一些限制。如果不创建对它的引用,就无法将它们放入 ViewModel(在某些人看来这可能会破坏 MVVM 模式)。好吧,有些人会争辩说“谁在乎,我需要让它工作,所以我得到了对 DataContext 的引用。”这没关系,但在我看来还有另一个更优雅的解决方案。一个监听那些的类更改值,将它们拉入您的 ViewModel——所谓的信使。

你们中的一些人可能使用过 MVVMLight、Prism 或类似的框架/工具包。如果你想在类库中使用它们,你会发现一些障碍,比如缺少 ViewModelLocator 等等。在工作中,我正在为我们的 LOB 应用程序开发通用用户控件。由于该控件涉及其视图中的许多值,因此我需要一种智能且快速的方法来将这些值放入我的 ViewModel 中。我用我自己的简单信使实现了它,使我能够避免我控制的任何框架/工具包。

我是这样做的。首先我创建了一个新的 Singleton 类 。如果您不知道单例是什么,只需单击前面句子中的链接即可。长话短说:Singleton 使类成为静态的,并确保所有其他类都在使用一个实例(以最终获得正确的值)。提示:可能由于时机不对,您仍然有多个实例。在这种情况下,您应该查看对 Singleton 实例的调用的不同实现方式。

在我的例子中,我使用的是简单的实现,如果没有,它会自动创建第一个实例:


 public class SimpleMessenger
    {
        private static SimpleMessenger _instance;
    public static SimpleMessenger Instance => _instance ?? (_instance = new SimpleMessenger());
 }

下一步是创建一个 EventHandler,它会在 SimpleMessenger 有新值时通知我们。创建您自己的 EventArgs 以传递给 EventHandler 是绝对有意义的。只需收集您想要在派生自 EventArgs 的类中提供的数据,并使 EventHandler 使用此类作为其事件数据:


 public class SimpleMessenger
    {
        private static SimpleMessenger _instance;
    public static SimpleMessenger Instance => _instance ?? (_instance = new SimpleMessenger());
 }

此类中最重要的功能是引发事件:


 public class SimpleMessenger
    {
        private static SimpleMessenger _instance;
    public static SimpleMessenger Instance => _instance ?? (_instance = new SimpleMessenger());
 }

我只使用了三个所需的基本值:更改的属性的名称、旧值和更新后的值。这已经使我能够在 View 和 ViewModel 之间发送数据,甚至可以发送到我无法控制的范围内。当然,您想了解如何使用我的 SimpleMessenger 发送“消息”。这也很简单。

首先,您需要获取对当前实例的引用:


 public class SimpleMessenger
    {
        private static SimpleMessenger _instance;
    public static SimpleMessenger Instance => _instance ?? (_instance = new SimpleMessenger());
 }

要发送数据,只需使用 RaiseMessageValueChanged 事件:


 public class SimpleMessenger
    {
        private static SimpleMessenger _instance;
    public static SimpleMessenger Instance => _instance ?? (_instance = new SimpleMessenger());
 }

最后但同样重要的是,我们还可以在其他地方读取这些值:


 public class SimpleMessenger
    {
        private static SimpleMessenger _instance;
    public static SimpleMessenger Instance => _instance ?? (_instance = new SimpleMessenger());
 }

如您所见,使用此类以解耦方式获取值很简单(就像 MVVM 模式所要求的那样)。当然,您仍然需要注意不要过度使用它。例如,我正在使用它来获取我的控件在 ViewModel 中具有的 DependencyProperties 的更改值(否则只能通过引用它才能实现)。

这个 SimpleMessenger 可能不如流行的框架/工具包中的功能强大,但对于在用户控件或小型应用程序中使用它应该非常适合。我附上了一个非常简单的项目来演示 SimpleMessenger。只需启动项目,然后使用鼠标调整应用程序窗口的大小。它会将根网格的大小写入控制台。

下载示例

一如既往,我希望这篇文章对你们中的一些人有所帮助。