MVVM的目标之一就是为了解耦View和ViewModel。View负责视图展示,ViewModel负责业务逻辑处理,尽量保证 View.xaml.cs中的简洁,不包含复杂的业务逻辑代码。

但是在实际情况中是View和ViewModel之间的交互方式还是比较复杂的,View和ViewModel的分离并不是界定的那么清晰。

比如以下两种场景:

1、如果需要某张视图页面弹出对话框、弹出子窗体、处理界面元素,播放动画等。如果这些操作都放在ViewModel中,就会导致ViewModel还是要去处理View级别的元素,造成View和ViewModel的依赖。

最好的办法就是ViewModel通知View应该做什么,而View监听接收到命令,并去处理这些界面需要处理的事情。

2、ViewModel和ViewModel之间也需要通过消息传递来完成一些交互。

而MVVM Light  的 Messenger类,提供了解决了上述两个问题的能力:

Messenger类用于应用程序的通信,接受者只能接受注册的消息类型,另外目标类型可以被指定,用Send<TMessage, TTarget>(TMessage message) 实现,

在这种情况下信息只能被传递如果接受者类型和目标参数类型匹配,message可以是任何简单或者复杂的对象,你可以用特定的消息类型或者创建你自己的类型继承自他们。

Messager类的主要交互模式就是信息接受和发送(可以理解为“发布消息服务”和“订阅消息服务”),是不是想到观察者模式了,哈哈哈。

MVVM Light Messenger 旨在通过简单的设计模式来精简此场景:任何对象都可以是接收端;任何对象都可以是发送端;任何对象都可以是消息。

如图:

1、View和ViewModel之间的消息交互

在View和ViewModel中进行消息器注册,相当于订阅服务。包含消息标志、消息参数和消息执行方法。如下:

消息标志token:ViewAlert,用于标识只阅读某个或者某些Sender发送的消息,并执行相应的处理,所以Sender那边的token要保持一致

执行方法Action:ShowReceiveInfo,用来执行接收到消息后的后续工作,注意这边是支持泛型能力的,所以传递参数很方便。

View.xaml.cs 代码如下:

   public partial class NessagerForView : Window
{
public NessagerForView()
{
InitializeComponent(); //消息标志token:ViewAlert,用于标识只阅读某个或者某些Sender发送的消息,并执行相应的处理,所以Sender那边的token要保持一致
//执行方法Action:ShowReceiveInfo,用来执行接收到消息后的后续工作,注意这边是支持泛型能力的,所以传递参数很方便。
Messenger.Default.Register<String>(this, "ViewAlert", ShowReceiveInfo);
this.DataContext = new MessengerRegisterForVViewModel();
//卸载当前(this)对象注册的所有MVVMLight消息
this.Unloaded += (sender, e) => Messenger.Default.Unregister(this);
} /// <summary>
/// 接收到消息后的后续工作:根据返回来的信息弹出消息框
/// </summary>
/// <param name="msg"></param>
private void ShowReceiveInfo(String msg)
{
MessageBox.Show(msg);
}
}

ViewModel代码:

  public class MessengerRegisterForVViewModel:ViewModelBase
{ public MessengerRegisterForVViewModel()
{ } #region 命令 private RelayCommand sendCommand;
/// <summary>
/// 发送命令
/// </summary>
public RelayCommand SendCommand
{
get
{
if (sendCommand == null)
sendCommand = new RelayCommand(() => ExcuteSendCommand());
return sendCommand; }
set { sendCommand = value; }
} private void ExcuteSendCommand()
{
Messenger.Default.Send<String>("ViewModel通知View弹出消息框", "ViewAlert"); //注意:token参数一致
} #endregion
}

结果:

2、ViewModel和ViewModel之间的消息交互,ViewModel和ViewModel在很多种场景下也需要通过消息传递来完成一些交互。

比如我打开了两个视图,一个视图是用户信息列表,一个视图是用户信息添加页面,如果想要达到添加信息之后,用户信息列表视图实时刷新,用消息通知无疑是一个很棒的体验。

我们来模拟一下:

MessengerRegisterViewModel代码:

   public class MessengerRegisterViewModel:ViewModelBase
{
public MessengerRegisterViewModel()
{
///Messenger:信使
///Recipient:收件人
Messenger.Default.Register<String>(this,"Message",ShowReceiveInfo);
} #region 属性 private String receiveInfo;
/// <summary>
/// 接收到信使传递过来的值
/// </summary>
public String ReceiveInfo
{
get { return receiveInfo; }
set { receiveInfo = value; RaisePropertyChanged(()=>ReceiveInfo); }
} #endregion #region 启动新窗口 private RelayCommand showSenderWindow; public RelayCommand ShowSenderWindow
{
get {
if (showSenderWindow == null)
showSenderWindow = new RelayCommand(()=>ExcuteShowSenderWindow());
return showSenderWindow; }
set { showSenderWindow = value; }
} private void ExcuteShowSenderWindow()
{
MessengerSenderView sender = new MessengerSenderView();
sender.Show();
} #endregion #region 辅助函数
/// <summary>
/// 显示收件的信息
/// </summary>
/// <param name="msg"></param>
private void ShowReceiveInfo(String msg)
{
ReceiveInfo += msg+"\n";
}
#endregion
}

MessengerSenderViewModel代码:

  public class MessengerSenderViewModel:ViewModelBase
{
public MessengerSenderViewModel()
{ } #region 属性
private String sendInfo;
/// <summary>
/// 发送消息
/// </summary>
public String SendInfo
{
get { return sendInfo; }
set { sendInfo = value; RaisePropertyChanged(()=>SendInfo); }
} #endregion #region 命令 private RelayCommand sendCommand;
/// <summary>
/// 发送命令
/// </summary>
public RelayCommand SendCommand
{
get
{
if (sendCommand == null)
sendCommand = new RelayCommand(() => ExcuteSendCommand());
return sendCommand; }
set { sendCommand = value; }
} private void ExcuteSendCommand()
{
Messenger.Default.Send<String>(SendInfo, "Message");
} #endregion
}

结果如下:

下载示例代码

转载请注明出处,谢谢

利刃 MVVMLight 9:Messenger的更多相关文章

  1. 利刃 MVVMLight 10:Messenger 深入

    1.Messager交互结构和消息类型 衔接上篇,Messeger是信使的意思,顾名思义,他的目是用于View和ViewModel 以及 ViewModel和ViewModel 之间的消息通知和接收. ...

  2. 利刃 MVVMLight

    已经很久没有写系列文章了,上一次是2012年写的HTLM5系列,想想我们应该是较早一批使用HTML5做项目的人. 相比我当时动不动100+的粉丝增长和两天3000+的阅读量,MVVM Light只能算 ...

  3. 利刃 MVVMLight 1:MVVMLight介绍以及在项目中的使用

    一.MVVM 和 MVVMLight介绍 MVVM是Model-View-ViewModel的简写.类似于目前比较流行的MVC.MVP设计模式,主要目的是为了分离视图(View)和模型(Model)的 ...

  4. 利刃 MVVMLight 2:Model、View、ViewModel结构以及全局视图模型注入器的说明

         上一篇我们已经介绍了如何使用NuGet把MVVMLight应用到我们的WPF项目中.这篇我们来了解下一个基本的MVVMLight框架所必须的结构和运行模式. MVVMLight安装之后,我们 ...

  5. 利刃 MVVMLight 3:双向数据绑定

          上篇我们已经了解了MVVM的框架结构和运行原理.这里我们来看一下伟大的双向数据绑定. 说到双向绑定,大家比较熟悉的应该就是AngularJS了,几乎所有的AngularJS 系列教程的开篇 ...

  6. 利刃 MVVMLight 5:绑定在表单验证上的应用

    表单验证是MVVM体系中的重要一块.而绑定除了推动 Model-View-ViewModel (MVVM) 模式松散耦合 逻辑.数据 和 UI定义 的关系之外,还为业务数据验证方案提供强大而灵活的支持 ...

  7. 利刃 MVVMLight 6:命令基础

    在MVVM Light框架中,事件是WPF应用程序中UI与后台代码进行交互的最主要方式,与传统方式不同,mvvm中主要通过绑定到命令来进行事件的处理, 因此要了解mvvm中处理事件的方式,就必须先熟悉 ...

  8. 利刃 MVVMLight 7:命令深入

    上面一篇我们大致了解了命令的基本使用方法和基础原理,但是实际在运用命令的时候会复杂的多,并且有各种各样的情况. 一.命令带参数的情况: 如果视图控件所绑定的命令想要传输参数,需要配置 CommandP ...

  9. 利刃 MVVMLight 4:绑定和绑定的各种使用场景

    一.绑定: 主要包含元素绑定和非元素绑定两种. 1.元素绑定,是绑定的最简单形式,源对象是WPF的元素,并且源对象的属性是依赖项属性. 根据我们之前的知识 ,依赖项属性具有内置的更改通知支持.所以当我 ...

随机推荐

  1. 微信JS初始化--微信JS系列文章(一)

    概述 微信JS的使用方法,官方文档已经描述得比较清楚了,这里我就不重复介绍了,本文意在提供现成的代码,供大家快速迭代开发,以及补充一下官方文档描述得不够清楚的地方,避免大家踩相同的坑. 微信JS初始化 ...

  2. python终端中退格键,方向键不能使用

    在安装Python的时候先安装 yum install readline-devel.x86_64 -y 如果python已经安装过了就重新安装 ./configure    make all mak ...

  3. 走入PHP-declare、ticks、encoding、include

    declare 结构用来设定一段代码的执行指令.declare 的语法和其它流程控制结构相似(该代码为语法格式,不是代码案例,无需敲打该代码): declare (directive) stateme ...

  4. 【前端调试手机页面】分享一款便捷的调试工具--spy-debugger

    spy-debugger  :  微信调试,各种WebView样式调试.手机浏览器的页面真机调试.便捷的远程调试手机页面.抓包工具,支持:HTTP/HTTPS,无需USB连接设备. github地址: ...

  5. IOS开发创建开发证书及发布App应用(四)——创建配置概要文件

    4.创建配置概要文件 继续上一篇所讲,今天写的这个是创建配置概要文件 依然在个人中心创建证书这里, 如果不知道的,可以查看以前写的 配置概要文件也分为两种 1)创建开发配置概要文件 2)创建发布配置概 ...

  6. 20155215 2016-2017-2 《Java程序设计》第5周学习总结

    学号 2006-2007-2 <Java程序设计>第5周学习总结 教材学习内容总结 第八章 尝试捕捉错误对象,try,catch. 如何抛出错误对象,throw语法. error代表系统错 ...

  7. 读书笔记 effective c++ Item 43 了解如何访问模板化基类中的名字

    1. 问题的引入——派生类不会发现模板基类中的名字 假设我们需要写一个应用,使用它可以为不同的公司发送消息.消息可以以加密或者明文(未加密)的方式被发送.如果在编译阶段我们有足够的信息来确定哪个信息会 ...

  8. Python之路-shell&计划任务

    开发脚本自动部署及监控1.编写脚本自动部署反向代理.web.nfs:要求: I.部署nginx反向代理三个web服务,调度算法使用加权轮询:           II.所有web服务使用共享存储nfs ...

  9. 老李分享:Uber究竟是用什么开发语言? 1

    老李分享:Uber究竟是用什么开发语言?   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:9 ...

  10. MySQL---连接器(python如何操作数据库媒介,基于python语言)

    MySQL — 连接器 连接器的概念 它们往往是一类Python包,或者是一类已经写好的Python库.这些库提供了我们Python去连接数据库服务器的基本功能. ​ 既然它是一个包,那么我们首先学会 ...