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
在这种情况下信息只能被传递如果接受者类型和目标参数类型匹配,message可以是任何简单或者复杂的对象,你可以用特定的消息类型或者创建你自己的类型继承自他们。
Messager类的主要交互模式就是信息接受和发送(可以理解为“发布消息服务”和“订阅消息服务”),是不是想到观察者模式了,哈哈哈。
MVVM Light Messenger 旨在通过简单的设计模式来精简此场景:任何对象都可以是接收端;任何对象都可以是发送端;任何对象都可以是消息。
1、View和ViewModel之间的消息交互
在View和ViewModel中进行消息器注册,相当于订阅服务。包含消息标志、消息参数和消息执行方法。如下:
消息标志token:ViewAlert,用于标识只阅读某个或者某些Sender发送的消息,并执行相应的处理,所以Sender那边的token要保持一致
执行方法Action:ShowReceiveInfo,用来执行接收到消息后的后续工作,注意这边是支持泛型能力的,所以传递参数很方便。
首先我们先熟悉一下基本的流程:
ViewModel代码:
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MessengerTest.ViewModel
{
public class MessengerRegisterForVViewModel:ViewModelBase
{
public MessengerRegisterForVViewModel()
{
}
#region 命令
private RelayCommand sendCommand;
///
/// 发送命令
///
public RelayCommand SendCommand
{
get
{
if (sendCommand == null)
{
sendCommand = new RelayCommand(() => ExcuteSendCommand());
}
return sendCommand;
}
set
{
sendCommand = value;
}
}
#endregion
private void ExcuteSendCommand()
{
Messenger.Default.Send("ViewModel通知View弹出消息框", "ViewAlert");
}
}
}
View.xaml.cs 代码如下
using GalaSoft.MvvmLight.Messaging;
using MessengerTest.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace MessengerTest
{
///
/// MessagerForView.xaml 的交互逻辑
///
public partial class MessagerForView : Window
{
public MessagerForView()
{
InitializeComponent();
///消息标志token:ViewAlert,用于标识只阅读某个或者某些Sender发送的消息,
///并执行相应的处理,
///所以Sender那边的token要保持一致
///执行方法Action:ShowReceiveInfo,用来执行接收到消息后的后续工作,
///注意这边是支持泛型能力的,所以传递参数很方便。
Messenger.Default.Register(this, "ViewAlert", ShowReceiveInfo);
this.DataContext = new MessengerRegisterForVViewModel();
///卸载当前(this)对象注册的所有MVVMLight消息
this.Unloaded += (sender, e) => Messenger.Default.Unregister(this);
}
///
/// 接收到消息后的后续工作:根据返回来的信息弹出消息框
///
///
private void ShowReceiveInfo(String msg)
{
MessageBox.Show(msg);
}
}
}
View.xaml代码:
结果如下:
2、ViewModel和ViewModel之间的消息交互,ViewModel和ViewModel在很多种场景下也需要通过消息传递来完成一些交互。
比如我打开了两个视图,一个视图是用户信息列表,一个视图是用户信息添加页面,如果想要达到添加信息之后,用户信息列表视图实时刷新,用消息通知无疑是一个很棒的体验。
我们来模拟一下:
首先,我们还是先看一下流程
MessengerSenderViewModel代码:
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MessengerInfo.ViewModel
{
public class MessengerSenderViewModel : ViewModelBase
{
public MessengerSenderViewModel()
{
}
#region 属性
private String sendInfo;
///
/// 发送消息
///
public String SendInfo
{
get { return sendInfo; }
set { sendInfo = value; RaisePropertyChanged(() => SendInfo); }
}
#endregion
#region 命令
private RelayCommand sendCommand;
///
/// 发送命令
///
public RelayCommand SendCommand
{
get
{
if (sendCommand == null)
sendCommand = new RelayCommand(() => ExcuteSendCommand());
return sendCommand;
}
set { sendCommand = value; }
}
private void ExcuteSendCommand()
{
Messenger.Default.Send(SendInfo, "Message");
}
#endregion
}
}
MessengerSenderView代码:
using MessengerInfo.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace MessengerInfo
{
///
/// MessengerSenderView.xaml 的交互逻辑
///
public partial class MessengerSenderView : Window
{
public MessengerSenderView()
{
InitializeComponent();
this.DataContext = new MessengerSenderViewModel();
}
}
}
MessengerRegisterViewModel 代码
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MessengerInfo.ViewModel
{
public class MessengerRegisterViewModel : ViewModelBase
{
public MessengerRegisterViewModel()
{
///Messenger:信使
///Recipient:收件人
Messenger.Default.Register(this, "Message", ShowReceiveInfo);
}
#region 属性
private String receiveInfo;
///
/// 接收到信使传递过来的值
///
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 辅助函数
///
/// 显示收件的信息
///
///
private void ShowReceiveInfo(String msg)
{
ReceiveInfo += msg + "\n";
}
#endregion
}
}
MessengerRegisterView 代码
using GalaSoft.MvvmLight.Messaging;
using MessengerInfo.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace MessengerInfo
{
///
/// MessengerRegisterView.xaml 的交互逻辑
///
public partial class MessengerRegisterView : Window
{
public MessengerRegisterView()
{
InitializeComponent();
this.DataContext = new MessengerRegisterViewModel();
//卸载当前(this)对象注册的所有MVVMLight消息
this.Unloaded += (sender, e) => Messenger.Default.Unregister(this);
}
}
}
结果如下: