【WPF】MVVM的消息机制

在WVM(Model-View-ViewModel)架构中,消息机制主要用于实现ViewModel与View之间的通信,同时保持它们的分离。这对于维护代码的清晰度和可测试性非常重要。在WPF(Windows Presentation Foundation)应用程序中,有几种常见的方法来实现MVVM中的消息传递机制。

1. 使用事件聚合(Event Aggregator)

事件聚合是一种设计模式,它允许发布者和订阅者通过一个中介进行通信,而不需要直接相互引用。Prism库提供了一个实现这个模式的EventAggregator类,它可以帮助你在ViewModel之间发送和接收消息。

  • 发布消息:创建一个继承自PubSubEvent<T>的事件类,并使用EventAggregator的GetEvent<Event>()方法获取该事件实例,然后调用Publish(T payload)方法发送消息。
  • 订阅消息:同样地,获取事件实例后,可以使用Subscribe(Action<T> action, bool keepSubscriberReferenceAlive)方法订阅该事件。

2. 使用Messenger或Mediator

Messenger是另一种实现松耦合消息传递的方法。MVVMLight Toolkit提供了一个Messenger类,支持不同类型的ViewModel之间传递消息。

  • 注册消息:在接收方ViewModel中使用Messenger.Default.Register<T>(this, action)方法注册特定类型的消息。
  • 发送消息:在发送方ViewModel中使用Messenger.Default.Send<T>(message)方法发送消息。

3. 使用命令(ICommand)

WPF提供了命令绑定机制,可以直接在View中绑定到ViewModel中的命令。这通常用于处理用户界面触发的动作,如按钮点击等。

  • 实现ICommand接口或使用RelayCommand(来自MVVMLight)等简化命令的创建。
  • 在XAML中,使用Command属性将UI元素(如Button)绑定到ViewModel中的命令。

4. 使用依赖属性(Dependency Property)和绑定(Binding)

虽然这不是一种传统意义上的“消息”机制,但通过绑定ViewModel的属性到View上的控件,可以在数据变化时自动更新UI,反之亦然。这是MVVM的核心概念之一。

选择合适的消息传递机制取决于具体的应用需求。对于需要解耦组件间交互的情况,事件聚合器或Messenger可能是更好的选择;而对于直接响应用户操作的场景,使用命令可能更加直接有效。

5.MVVMLight Toolkit示例

假设我们有两个ViewModel:MainViewModelSecondViewModel。当用户在MainView上点击按钮时,我们需要通知SecondViewModel更新其显示的内容。

5.1. 添加MVVMLight Toolkit

首先,确保你的项目中包含了MVVMLight Toolkit。你可以通过NuGet包管理器安装它:

Install-Package MvvmLightLibs

5.2. 创建Messenger消息类

创建一个简单的类用于携带消息数据:

public class UpdateMessage
{public string NewContent { get; set; }
}

5.3. 在SecondViewModel中注册接收消息

SecondViewModel中,注册监听特定类型的消息,并定义接收到消息后的操作: 

public class SecondViewModel : ViewModelBase
{public SecondViewModel(){Messenger.Default.Register<UpdateMessage>(this, (action) =>{// 更新属性,触发UI更新DisplayContent = action.NewContent;});}private string _displayContent;public string DisplayContent{get => _displayContent;set => Set(ref _displayContent, value);}
}

 5.4. 在MainViewModel中发送消息

MainViewModel中,当你想要通知SecondViewModel更新内容时,可以发送一个消息:

public class MainViewModel : ViewModelBase
{public ICommand SendMessageCommand { get; private set; }public MainViewModel(){SendMessageCommand = new RelayCommand(() =>{// 发送消息给SecondViewModelMessenger.Default.Send(new UpdateMessage { NewContent = "Hello from MainViewModel!" });});}
}

在这个例子中,当用户触发SendMessageCommand(例如通过点击按钮),MainViewModel会发送一条UpdateMessage消息。由于SecondViewModel已经注册了这种类型的消息,它将会接收到这条消息并更新其DisplayContent属性,进而更新相关的UI部分。

 

6.其他几种方案

6.1. 使用Prism框架

Prism是一个强大的框架,专为构建松散耦合、可维护和可测试的XAML应用程序而设计。它提供了一个EventAggregator服务,可以用于发布和订阅事件,从而实现在不同ViewModel或组件之间的通信。

  • 优点:支持模块化开发,提供多种实用工具和服务。
  • 缺点:对于简单的项目来说可能过于重量级。

6.2. 自定义消息传递系统

如果你不想引入额外的库,可以创建自己的消息传递系统。这通常涉及到创建一个共享的消息中心,允许发送者发布消息,接收者则可以订阅感兴趣的消息类型。 然后在你的ViewModel中订阅或发送消息。

public class MessageCenter
{public event EventHandler<string> OnMessageReceived;public void SendMessage(string message){OnMessageReceived?.Invoke(this, message);}
}

6.3. 使用依赖属性和绑定

虽然这不是传统意义上的消息机制,但是通过依赖属性和数据绑定也可以达到类似的效果。例如,你可以将一个ViewModel中的属性绑定到另一个ViewModel中,当属性值发生变化时,UI也会自动更新。

6.4. 使用.NET内建的事件(Event)

直接在ViewModel中定义事件,并让需要监听这些事件的View或其他ViewModel进行订阅。这是一种非常基础的方法,适用于简单的场景。然后在另一个ViewModel中订阅此事件。

public class MainViewModel
{public event EventHandler<string> MessageSent;private void OnSendMessage(string message){MessageSent?.Invoke(this, message);}
}

每种方法都有其适用的场景和优缺点。选择哪种方法取决于你的具体需求、项目的复杂度以及团队对特定技术的熟悉程度。对于小型应用或者简单的消息传递需求,自定义解决方案或.NET内建的事件可能就足够了;而对于更复杂的场景,考虑使用Prism或MVVMLight这样的框架可能会更加合适。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/84772.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

以楼宇自控关键技术,夯实现代低碳建筑发展重要基础

当“碳达峰、碳中和”成为全球发展共识&#xff0c;建筑行业作为能源消耗与碳排放的重要领域&#xff0c;正加速向低碳化转型。在这场绿色变革中&#xff0c;楼宇自控技术凭借对建筑设备的智能管控与能源优化能力&#xff0c;成为现代低碳建筑建设的核心支撑。从数据采集到智能…

西电【信息与内容安全】课程期末复习笔记

西电【信息与内容安全】课程期末复习笔记 来自2022年春的古早遗留档案&#xff0c;有人需要这个&#xff0c;我就再发一下吧。 ‍ 平时成绩&#xff1a; 10%。线上&#xff1a; 10% &#xff08;线上学习内容&#xff0c; 共 100 分。&#xff09;实验&#xff1a; 10% &#…

【论文阅读笔记】ICLR 2025 | 解析Ref-Gaussian如何实现高质量可交互反射渲染

Reflective Gaussian Splatting Info 会议 【ICLR 2025】 作者 复旦大学&#xff0c;萨里大学&#xff1b;复旦张力教授团队 Github地址 https://github.com/fudan-zvg/ref-gaussian.git Project地址 https://fudan-zvg.github.io/ref-gaussian/ Abstract 新视图合成得益…

面向GPU、CPU及机器学习加速器的机器学习编译器

机器学习编译器概述 机器学习编译器是一种专门针对机器学习工作负载设计的工具&#xff0c;旨在将高层模型描述&#xff08;如TensorFlow或PyTorch模型&#xff09;高效编译为可在不同硬件&#xff08;如GPU、CPU或专用加速器&#xff09;上执行的底层代码。其核心目标是优化计…

论文分类打榜赛Baseline(2):InternLM昇腾硬件微调实践

本文来自社区投稿&#xff0c;作者丁一超 书生大模型实战营第5期已正式启动&#xff0c;本期实战营新增「论文分类打榜赛」&#xff0c;以帮助学员更好地掌握大模型技能。 本文将手把手带领大家如何基于昇腾微调 InternLM 模型&#xff0c;轻松上手论文自动分类任务。从环境配…

mac安装mvnd结合idea

mac安装mvnd结合idea hi&#xff0c;我是阿昌&#xff0c;今天记录一下mac系统下如何安装mvnd同时通过maven-helper插件配置mvnd命令&#xff0c;提升编译速度&#xff1b; 0、前言 如果你正在开发一个由大量模块组成的大型项目&#xff0c;Gradle可以让大型项目构建的更快&…

扩展模块--QWebEngine功能及架构解析

Qt WebEngine 模块在 Qt 6.9 中提供了基于 Chromium 的网页渲染引擎功能。 一、主要功能 核心功能 网页渲染引擎 基于 Chromium 项目的最新稳定版本 支持现代 HTML5、CSS3 和 JavaScript 标准 主要组件 QWebEngineView - 用于显示网页内容的 widget QWebEnginePage - 表示…

Spring Boot Admin监控

1、概述 Spring Boot Admin 是一款用于监控 Spring Boot 应用程序的开源工具&#xff0c;可帮助开发者实时监控应用的运行状态、性能指标、日志信息等。 2、核心功能 应用状态监控 显示应用是否在线、启动时间、运行时长等基础信息。监控 JVM 相关指标&#xff1a;内存使用情…

【QT】QTableView自定义样式:仅显示行间隔、隐藏列间隔、表头样式、表格样式、单行选中等

目录 0.背景 1.详细代码 0.背景 项目需要&#xff0c;我有一个自定义的类Steer_Electrode_Table&#xff0c;是一个QTableView&#xff1b; 记录一下QTableView修改前后的样式&#xff0c;仅供参考 看一下我修改前后的样式对比 1.详细代码 void Steer_Electrode_Table::init…

mvnd-快速打包maven项目

mvnd 一、简介一、定位与背景二、核心架构与加速原理三、使用注意事项 二、下载安装三、idea集成mvnd插件四、打包测试时长 一、简介 mvnd&#xff08;Maven Daemon&#xff09;是Apache Maven团队推出的高性能构建工具&#xff0c;旨在解决传统Maven构建速度慢的问题。它通过…

C++ 中的尾调用优化TCO:原理、实战与汇编分析

C尾调用优化 什么是尾调用&#xff1f;描述无返回值函数最后调用函数也可能做尾调用优化 例子关键特征&#xff08;写法&#xff09; 尾调用和尾递归的区别&#xff1f;为什么尾调用优化可以提高效率&#xff1f;通常的递归调用&#xff1a;尾调用优化&#xff1a;为什么栈帧复…

Java集合 - ArrayList底层源码解析

下面开始对 Java 中 ArrayList 的深度源码分析&#xff0c;基于 JDK 8 的实现&#xff08;后续版本略有差异&#xff0c;但核心逻辑一致&#xff09;。我们将从 类结构、扩容机制、核心方法实现、性能优化、线程安全问题 等角度进行详细解析 一、类结构与核心字段 1. 类继承关…

【Qt】Qt控件

文章目录 Qt控件Layout Spacer垂直布局QVBoxLayout水平排列布局QHBoxLayout网格布局 QGridLayout表格布局 QFormLayout Button Contain命令按钮Push Button工具按钮Tool Button单选按钮Radio Button复选框按钮Check Box命令链接按钮Command Link Button按钮盒Button Box组合框G…

PHP基础-运算符

PHP 的运算符是编程中非常基础但又非常重要的一部分&#xff0c;掌握它们能让你更灵活地处理各种逻辑、计算和流程控制。 算术运算符 用于基本数学运算&#xff1a; 运算符含义示例加法$a $b-减法$a - $b*乘法$a * $b/除法$a / $b%取模$a % $b 示例&#xff1a; <?ph…

AR珠宝佩戴与传统的珠宝购物有哪些区别?​

AR 珠宝佩戴与传统的珠宝购物究竟存在着哪些显著区别呢?在传统的珠宝购物模式里&#xff0c;顾客往往需要花费时间和精力前往实体珠宝店。踏入店内&#xff0c;首先映入眼帘的便是那一排排的玻璃展柜&#xff0c;此时&#xff0c;销售人员会热情地走上前&#xff0c;小心翼翼地…

华为云CAE部署spring cloud服务

1 概述 华为云CAE&#xff08;Cloud Application Engine云应用引擎&#xff09;是一个面向WEB、微服务应用的Serverless托管服务&#xff0c;提供极速部署、极低成本、极简运维的一站式应用托管方案。支持从源码、软件包、镜像包快速发布应用&#xff0c;秒级弹性伸缩、按量付…

【技术工具】源码管理 - GIT工具

【技术工具】源码管理 - GIT工具 1 前言 之前参考语雀一位大佬的&#xff0c;但链接找不到了&#xff0c;仅供参考。 1、检查空白错误 //确认将提交的内容中有无空白信息 git diff --check 2、尝试让每一个提交成为一个逻辑的独立变更集 尽量使每笔提交都成为独立的patch&a…

Objective-c Block 面试题

以下是对我们这整段关于 Objective-C 中 Block、__block 修饰符、内存管理行为、生命周期等内容的全面总结&#xff0c;并附带了一套适合面试准备的面试题集&#xff08;带答案&#xff09;。 &#x1f9e0; 一、知识总结&#xff1a;Objective-C Block __block 修饰符 ✅ Bl…

AndroidMJ-基础-05

基础part5: 9:测试相关 postman genemotion espresso 10:性能相关 profiler 9.测试相关 espresso相关&#xff1a; Android Espresso 自动化测试指南&#xff08;Java 版&#xff09;-CSDN博客 10.性能相关 profiler相关&#xff1a; AndroidStudio之内层泄漏工具Profiler…

R语言 | 如何使用R书写html文档?

更灵活的书写方式&#xff0c;可以直接看3. 1. 可用函数 cat()函数writeLines()函数sink()函数重定向输出到HTML文件 小结&#xff1a;cat()适合简单HTML&#xff0c;writeLines()适合多行内容&#xff0c;sink()适合复杂场景。 说明&#xff1a;尽可能不用R包&#xff0c;减…