Messenger在MVVM模式中的应用
Messenger在MVVM模式中的应用
Messenger在MVVM中应用的前提
我们知道在MVVM架构中,系统平台的Silverlight客户端界面开发和业务逻辑已经被分开,XAML是SL的主要部分,界面设计者只需要绑定ViewModel里的数据即可。但是在ViewModel里有些时候是需要界面发出响应的,在这种情况下,Messenger显示出它的用处。
Messenger的架构

Messager构件代码
定义Imessager接口
注册一个接收消息的类型,比如某一控件来接收消息
void Register<TMessage>(object recipient, Action<TMessage> action);
给最近注册的类型发送消息
void Send<TMessage, TTarget>(TMessage message);
取消最近注册的类型,当执行该句后,不再接收任何消息
void Unregister(object recipient);
实现Imessager接口
public class Messenger : IMessenger
{
private static Messenger _defaultInstance;
private Dictionary<Type, List<WeakActionAndToken>> _recipientsOfSubclassesAction;
private Dictionary<Type, List<WeakActionAndToken>> _recipientsStrictAction;
public static Messenger Default
{
get
{
if (_defaultInstance == null)
{
_defaultInstance = new Messenger();
}
return _defaultInstance;
}
}
public static void OverrideDefault(Messenger newMessenger)
{
_defaultInstance = newMessenger;
}
public static void Reset()
{
_defaultInstance = null;
}
public virtual void Register<TMessage>(object recipient, Action<TMessage> action)
{
Register(recipient, null, false, action);
}
public virtual void Register<TMessage>(object recipient, bool receiveDerivedMessagesToo, Action<TMessage> action)
{
Register(recipient, null, receiveDerivedMessagesToo, action);
}
public virtual void Register<TMessage>(object recipient, object token, Action<TMessage> action)
{
Register(recipient, token, false, action);
}
public virtual void Register<TMessage>(
object recipient,
object token,
bool receiveDerivedMessagesToo,
Action<TMessage> action)
{
var messageType = typeof(TMessage);
Dictionary<Type, List<WeakActionAndToken>> recipients;
if (receiveDerivedMessagesToo)
{
if (_recipientsOfSubclassesAction == null)
{
_recipientsOfSubclassesAction = new Dictionary<Type, List<WeakActionAndToken>>();
}
recipients = _recipientsOfSubclassesAction;
}
else
{
if (_recipientsStrictAction == null)
{
_recipientsStrictAction = new Dictionary<Type, List<WeakActionAndToken>>();
}
recipients = _recipientsStrictAction;
}
List<WeakActionAndToken> list;
if (!recipients.ContainsKey(messageType))
{
list = new List<WeakActionAndToken>();
recipients.Add(messageType, list);
}
else
{
list = recipients[messageType];
}
var weakAction = new WeakAction<TMessage>(recipient, action);
var item = new WeakActionAndToken
{
Action = weakAction,
Token = token
};
list.Add(item);
Cleanup();
}
public virtual void Send<TMessage>(TMessage message)
{
SendToTargetOrType(message, null, null);
}
[SuppressMessage(
"Microsoft.Design",
"CA1004:GenericMethodsShouldProvideTypeParameter",
Justification = "This syntax is more convenient than other alternatives.")]
public virtual void Send<TMessage, TTarget>(TMessage message)
{
SendToTargetOrType(message, typeof(TTarget), null);
}
public virtual void Send<TMessage>(TMessage message, object token)
{
SendToTargetOrType(message, null, token);
}
/// <summary>
public virtual void Unregister(object recipient)
{
UnregisterFromLists(recipient, _recipientsOfSubclassesAction);
UnregisterFromLists(recipient, _recipientsStrictAction);
}
[SuppressMessage(
"Microsoft.Design",
"CA1004:GenericMethodsShouldProvideTypeParameter",
Justification =
"The type parameter TMessage identifies the message type that the recipient wants to unregister for.")]
public virtual void Unregister<TMessage>(object recipient)
{
Unregister<TMessage>(recipient, null);
}
public virtual void Unregister<TMessage>(object recipient, Action<TMessage> action)
{
UnregisterFromLists(recipient, action, _recipientsStrictAction);
UnregisterFromLists(recipient, action, _recipientsOfSubclassesAction);
Cleanup();
}
private static void CleanupList(IDictionary<Type, List<WeakActionAndToken>> lists)
{
if (lists == null)
{
return;
}
var listsToRemove = new List<Type>();
foreach (var list in lists)
{
var recipientsToRemove = new List<WeakActionAndToken>();
foreach (var item in list.Value)
{
if (item.Action == null
|| !item.Action.IsAlive)
{
recipientsToRemove.Add(item);
}
}
foreach (var recipient in recipientsToRemove)
{
list.Value.Remove(recipient);
}
if (list.Value.Count == 0)
{
listsToRemove.Add(list.Key);
}
}
foreach (var key in listsToRemove)
{
lists.Remove(key);
}
}
private static bool Implements(Type instanceType, Type interfaceType)
{
if (interfaceType == null
|| instanceType == null)
{
return false;
}
var interfaces = instanceType.GetInterfaces();
foreach (var currentInterface in interfaces)
{
if (currentInterface == interfaceType)
{
return true;
}
}
return false;
}
private static void SendToList<TMessage>(
TMessage message,
IEnumerable<WeakActionAndToken> list,
Type messageTargetType,
object token)
{
if (list != null)
{
var listClone = list.Take(list.Count()).ToList();
foreach (var item in listClone)
{
var executeAction = item.Action as IExecuteWithObject;
if (executeAction != null
&& item.Action.IsAlive
&& item.Action.Target != null
&& (messageTargetType == null
|| item.Action.Target.GetType() == messageTargetType
|| Implements(item.Action.Target.GetType(), messageTargetType))
&& ((item.Token == null && token == null)
|| item.Token != null && item.Token.Equals(token)))
{
executeAction.ExecuteWithObject(message);
}
}
}
}
private static void UnregisterFromLists(object recipient, Dictionary<Type, List<WeakActionAndToken>> lists)
{
if (recipient == null
|| lists == null
|| lists.Count == 0)
{
return;
}
lock (lists)
{
foreach (var messageType in lists.Keys)
{
foreach (var item in lists[messageType])
{
var weakAction = item.Action;
if (weakAction != null
&& recipient == weakAction.Target)
{
weakAction.MarkForDeletion();
}
}
}
}
}
private static void UnregisterFromLists<TMessage>(
object recipient,
Action<TMessage> action,
Dictionary<Type, List<WeakActionAndToken>> lists)
{
var messageType = typeof(TMessage);
if (recipient == null
|| lists == null
|| lists.Count == 0
|| !lists.ContainsKey(messageType))
{
return;
}
lock (lists)
{
foreach (var item in lists[messageType])
{
var weakActionCasted = item.Action as WeakAction<TMessage>;
if (weakActionCasted != null
&& recipient == weakActionCasted.Target
&& (action == null
|| action == weakActionCasted.Action))
{
item.Action.MarkForDeletion();
}
}
}
}
private void Cleanup()
{
CleanupList(_recipientsOfSubclassesAction);
CleanupList(_recipientsStrictAction);
}
private void SendToTargetOrType<TMessage>(TMessage message, Type messageTargetType, object token)
{
var messageType = typeof(TMessage);
if (_recipientsOfSubclassesAction != null)
{
var listClone = _recipientsOfSubclassesAction.Keys.Take(_recipientsOfSubclassesAction.Count()).ToList();
foreach (var type in listClone)
{
List<WeakActionAndToken> list = null;
if (messageType == type
|| messageType.IsSubclassOf(type)
|| Implements(messageType, type))
{
list = _recipientsOfSubclassesAction[type];
}
SendToList(message, list, messageTargetType, token);
}
}
if (_recipientsStrictAction != null)
{
if (_recipientsStrictAction.ContainsKey(messageType))
{
var list = _recipientsStrictAction[messageType];
SendToList(message, list, messageTargetType, token);
}
}
Cleanup();
}
private struct WeakActionAndToken
{
public WeakAction Action;
public object Token;
}
}
Messager在MVVM的实例
在ViewModel端
public void UpdateJob(object sender, RoutedEventArgs v)
{
var focusrow = (JobMVVMClient.JobBL.View_T_SegmentJob)SelectRow;
if (focusrow != null)
{
JobMVVMClient.JobBL.JobBLClient Job = new JobMVVMClient.JobBL.JobBLClient();
var row = (JobMVVMClient.JobBL.View_T_SegmentJob)selectRow;
if (row.班次号 == null || row.班组号 == null
|| row.计划结束时间 == null || row.计划开始时间 == null || row.投产量 == 0.0)
return;
Job.UpdateSegmentJobBySomeThingCompleted += (s, e) =>
{
if (e.Result)
{
MessageBox.Show(PromptString.UpdateJobYes);
foreach (var element in jobModel.Gradeinfo)
{
if (element.DetailID == row.班次号.ToString())
row.班次 = element.DetailName;
}
foreach (var element in jobModel.Groupinfo)
{
if (element.DetailID == row.班组号.ToString())
row.班组 = element.DetailName;
}
}
};
Messenger.Default.Send<bool?,JobMVVMClinet.Views.JobPlanUpdateView>(true);
//给位于View层中的JobPlanUpdateView这个界面发送bool消息,这个消息是true.
Job.UpdateSegmentJobBySomeThingAsync(row.工单ID, row.投产量, (DateTime)row.计划开始时间, (DateTime)row.计划结束时间, (int)row.班次号, (int)row.班组号);
Job.CloseAsync();
}
}
在VIEW端
public partial class JobPlanUpdateView : ChildWindow
{
public JobPlanUpdateView(CreateJobViewModel model)
{
InitializeComponent();
DataContext = model;
Messenger.Default.Register<bool?>(this, m => this.DialogResult = m);
//注册接收消息,并且做出响应处理
}
}
Messager总结
消息在MVVM中广泛应用,更好的运用MESSAGER能更好的处理View与ViewModel的关系,为MVVM添加喝彩。
Messenger在MVVM模式中的应用的更多相关文章
- 在MVVM模式中,按钮Click事件的绑定方法
在MVVM模式中,我们将Button的方法写到ViewModel中,然后绑定到前端界面.通常的做法是写一个类,继承ICommand接口,然而如果按钮比较多的话,就需要写很多的类,对于后期维护造成很大的 ...
- silverlighter下MVVM模式中利用Behavior和TargetedTriggerAction实现文本框的一些特效
在silverlight一般开发模式中,给文本框添加一些事件是轻而易举的,然而MVVM开发模式中,想要给文本框添加一些事件并非那么容易,因为MVVM模式中,只有ICommand接口,而且也只有Butt ...
- “Win10 UAP 开发系列”之 在MVVM模式中控制ListView滚动位置
这个扩展属性从WP8.1就开始用了,主要是为了解决MVVM模式中无法直接控制ListView滚动位置的问题.比如在VM中刷新了数据,需要将View中的ListView滚动到顶部,ListView只有一 ...
- WPF MVVM模式中,通过命令实现窗体拖动、跳转以及显隐控制
原文:WPF MVVM模式中,通过命令实现窗体拖动.跳转以及显隐控制 在WPF中使用MVVM模式,可以让我们的程序实现界面与功能的分离,方便开发,易于维护.但是,很多初学者会在使用MVVM的过程中遇到 ...
- WPF ContextMenu 在MVVM模式中绑定 Command及使用CommandParameter传参
原文:WPF ContextMenu 在MVVM模式中绑定 Command及使用CommandParameter传参 ContextMenu无论定义在.cs或.xaml文件中,都不继承父级的DataC ...
- 深入理解MVVM模式中Silverlight的Trigger、Action和Behavior及Silverlight的继承机制
接触Silverlight已经有两三个月了,开始一直感觉他和Winform很相似,拖拖控件就行了,所以一直把经历放在了研究后台和服务器交互和性能优化上面,很少去仔细研究Silverlight的页面.前 ...
- MVVM模式中WPF数据的完全绑定
一:截图,描述:将后台代码的姓名.年龄绑定到文本框,单击”增加年龄“--年龄自+1,单击”显示年龄“--弹出年龄的显示对话框,实现了从文本框修改年龄和后台更改年龄并显示到文本框 运行结果和解决方案管理 ...
- MVVM模式中ViewModel和View、Model有什么区别
Model:很简单,就是业务逻辑相关的数据对象,通常从数据库映射而来,我们可以说是与数据库对应的model. View:也很简单,就是展现出来的用户界面. 基本上,绝大多数软件所做的工作无非就是从数据 ...
- XAML: 在 MVVM 模式中,关于绑定的几处技巧
以下会提到三个绑定的技巧,分别是 在 ListView 中为 ListViewItem 的 MenuFlyout 绑定 Command: 在 ListView 的 事件中绑定所选择项目,即其 Sele ...
随机推荐
- [Swift]LeetCode70. 爬楼梯 | Climbing Stairs
You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb ...
- 树莓派pwm驱动好盈电调及伺服电机
本文讲述如何通过树莓派的硬件PWM控制好盈电调来驱动RC车子的前进后退,以及如何驱动伺服电机来控制车子转向. 1. 好盈电调简介 车子上的电调型号为:WP-10BLS-A-RTR,在好盈官网并没有搜到 ...
- CentOS6.9下离线部署Django项目
最近项目服务器变动,研究了CentOS6.9下httpd2.4+django1.11.16+python3.6+PostgreSQL的部署,之前还有一个ubuntu16.04下的部署等以后整理好后再来 ...
- 解决classNotFound的问题的思路
用Ctrl+Shift+t可以查看class,对于报错信息,我们把没有找到的class放到查找框里进行查看,找到之后把这个jar包放到WEB-INF的lib目录下,build path一下就可以了. ...
- 【Spark篇】---SparkSQL初始和创建DataFrame的几种方式
一.前述 1.SparkSQL介绍 Hive是Shark的前身,Shark是SparkSQL的前身,SparkSQL产生的根本原因是其完全脱离了Hive的限制. SparkSQL支持查询原 ...
- Python内置函数(40)——map
英文文档: map(function, iterable, ...) Return an iterator that applies function to every item of iterabl ...
- .NET Core实战项目之CMS 第十一章 开发篇-数据库生成及实体代码生成器开发
上篇给大家从零开始搭建了一个我们的ASP.NET Core CMS系统的开发框架,具体为什么那样设计我也已经在第十篇文章中进行了说明.不过文章发布后很多人都说了这样的分层不是很合理,什么数据库实体应该 ...
- 『素数 Prime判定和线性欧拉筛法 The sieve of Euler』
素数(Prime)及判定 定义 素数又称质数,一个大于1的自然数,除了1和它自身外,不能整除其他自然数的数叫做质数,否则称为合数. 1既不是素数也不是合数. 判定 如何判定一个数是否是素数呢?显然,我 ...
- 《HelloGitHub月刊》第 07 期
最近工作上的事比较多,<HelloGitHub>月刊第07期拖到月底才发. 本期月刊对logo和月刊的排版进行了优化,不知道大家的反馈如何,还望大家多多反馈,让<HelloGitHu ...
- leetcode — best-time-to-buy-and-sell-stock-ii
/** * Source : https://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ * * * * Say you ...