利刃 MVVMLight 9:Messenger
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 代码如下:
1 public partial class NessagerForView : Window 2 { 3 public NessagerForView() 4 { 5 InitializeComponent(); 6 7 //消息标志token:ViewAlert,用于标识只阅读某个或者某些Sender发送的消息,并执行相应的处理,所以Sender那边的token要保持一致 8 //执行方法Action:ShowReceiveInfo,用来执行接收到消息后的后续工作,注意这边是支持泛型能力的,所以传递参数很方便。 9 Messenger.Default.Register<String>(this, "ViewAlert", ShowReceiveInfo); 10 this.DataContext = new MessengerRegisterForVViewModel(); 11 //卸载当前(this)对象注册的所有MVVMLight消息 12 this.Unloaded += (sender, e) => Messenger.Default.Unregister(this); 13 } 14 15 /// <summary> 16 /// 接收到消息后的后续工作:根据返回来的信息弹出消息框 17 /// </summary> 18 /// <param name="msg"></param> 19 private void ShowReceiveInfo(String msg) 20 { 21 MessageBox.Show(msg); 22 } 23 }
ViewModel代码:
1 public class MessengerRegisterForVViewModel:ViewModelBase 2 { 3 4 public MessengerRegisterForVViewModel() 5 { 6 7 } 8 9 #region 命令 10 11 private RelayCommand sendCommand; 12 /// <summary> 13 /// 发送命令 14 /// </summary> 15 public RelayCommand SendCommand 16 { 17 get 18 { 19 if (sendCommand == null) 20 sendCommand = new RelayCommand(() => ExcuteSendCommand()); 21 return sendCommand; 22 23 } 24 set { sendCommand = value; } 25 } 26 27 private void ExcuteSendCommand() 28 { 29 Messenger.Default.Send<String>("ViewModel通知View弹出消息框", "ViewAlert"); //注意:token参数一致 30 } 31 32 #endregion 33 }
结果:
2、ViewModel和ViewModel之间的消息交互,ViewModel和ViewModel在很多种场景下也需要通过消息传递来完成一些交互。
比如我打开了两个视图,一个视图是用户信息列表,一个视图是用户信息添加页面,如果想要达到添加信息之后,用户信息列表视图实时刷新,用消息通知无疑是一个很棒的体验。
我们来模拟一下:
MessengerRegisterViewModel代码:
1 public class MessengerRegisterViewModel:ViewModelBase 2 { 3 public MessengerRegisterViewModel() 4 { 5 ///Messenger:信使 6 ///Recipient:收件人 7 Messenger.Default.Register<String>(this,"Message",ShowReceiveInfo); 8 } 9 10 11 #region 属性 12 13 private String receiveInfo; 14 /// <summary> 15 /// 接收到信使传递过来的值 16 /// </summary> 17 public String ReceiveInfo 18 { 19 get { return receiveInfo; } 20 set { receiveInfo = value; RaisePropertyChanged(()=>ReceiveInfo); } 21 } 22 23 #endregion 24 25 26 #region 启动新窗口 27 28 private RelayCommand showSenderWindow; 29 30 public RelayCommand ShowSenderWindow 31 { 32 get { 33 if (showSenderWindow == null) 34 showSenderWindow = new RelayCommand(()=>ExcuteShowSenderWindow()); 35 return showSenderWindow; 36 37 } 38 set { showSenderWindow = value; } 39 } 40 41 private void ExcuteShowSenderWindow() 42 { 43 MessengerSenderView sender = new MessengerSenderView(); 44 sender.Show(); 45 } 46 47 #endregion 48 49 50 #region 辅助函数 51 /// <summary> 52 /// 显示收件的信息 53 /// </summary> 54 /// <param name="msg"></param> 55 private void ShowReceiveInfo(String msg) 56 { 57 ReceiveInfo += msg+"\n"; 58 } 59 #endregion 60 }
MessengerSenderViewModel代码:
1 public class MessengerSenderViewModel:ViewModelBase 2 { 3 public MessengerSenderViewModel() 4 { 5 6 } 7 8 #region 属性 9 private String sendInfo; 10 /// <summary> 11 /// 发送消息 12 /// </summary> 13 public String SendInfo 14 { 15 get { return sendInfo; } 16 set { sendInfo = value; RaisePropertyChanged(()=>SendInfo); } 17 } 18 19 #endregion 20 21 #region 命令 22 23 private RelayCommand sendCommand; 24 /// <summary> 25 /// 发送命令 26 /// </summary> 27 public RelayCommand SendCommand 28 { 29 get 30 { 31 if (sendCommand == null) 32 sendCommand = new RelayCommand(() => ExcuteSendCommand()); 33 return sendCommand; 34 35 } 36 set { sendCommand = value; } 37 } 38 39 private void ExcuteSendCommand() 40 { 41 Messenger.Default.Send<String>(SendInfo, "Message"); 42 } 43 44 #endregion 45 }
结果如下:
转载请注明出处,谢谢