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模式中的应用的更多相关文章

  1. 在MVVM模式中,按钮Click事件的绑定方法

    在MVVM模式中,我们将Button的方法写到ViewModel中,然后绑定到前端界面.通常的做法是写一个类,继承ICommand接口,然而如果按钮比较多的话,就需要写很多的类,对于后期维护造成很大的 ...

  2. silverlighter下MVVM模式中利用Behavior和TargetedTriggerAction实现文本框的一些特效

    在silverlight一般开发模式中,给文本框添加一些事件是轻而易举的,然而MVVM开发模式中,想要给文本框添加一些事件并非那么容易,因为MVVM模式中,只有ICommand接口,而且也只有Butt ...

  3. “Win10 UAP 开发系列”之 在MVVM模式中控制ListView滚动位置

    这个扩展属性从WP8.1就开始用了,主要是为了解决MVVM模式中无法直接控制ListView滚动位置的问题.比如在VM中刷新了数据,需要将View中的ListView滚动到顶部,ListView只有一 ...

  4. WPF MVVM模式中,通过命令实现窗体拖动、跳转以及显隐控制

    原文:WPF MVVM模式中,通过命令实现窗体拖动.跳转以及显隐控制 在WPF中使用MVVM模式,可以让我们的程序实现界面与功能的分离,方便开发,易于维护.但是,很多初学者会在使用MVVM的过程中遇到 ...

  5. WPF ContextMenu 在MVVM模式中绑定 Command及使用CommandParameter传参

    原文:WPF ContextMenu 在MVVM模式中绑定 Command及使用CommandParameter传参 ContextMenu无论定义在.cs或.xaml文件中,都不继承父级的DataC ...

  6. 深入理解MVVM模式中Silverlight的Trigger、Action和Behavior及Silverlight的继承机制

    接触Silverlight已经有两三个月了,开始一直感觉他和Winform很相似,拖拖控件就行了,所以一直把经历放在了研究后台和服务器交互和性能优化上面,很少去仔细研究Silverlight的页面.前 ...

  7. MVVM模式中WPF数据的完全绑定

    一:截图,描述:将后台代码的姓名.年龄绑定到文本框,单击”增加年龄“--年龄自+1,单击”显示年龄“--弹出年龄的显示对话框,实现了从文本框修改年龄和后台更改年龄并显示到文本框 运行结果和解决方案管理 ...

  8. MVVM模式中ViewModel和View、Model有什么区别

    Model:很简单,就是业务逻辑相关的数据对象,通常从数据库映射而来,我们可以说是与数据库对应的model. View:也很简单,就是展现出来的用户界面. 基本上,绝大多数软件所做的工作无非就是从数据 ...

  9. XAML: 在 MVVM 模式中,关于绑定的几处技巧

    以下会提到三个绑定的技巧,分别是 在 ListView 中为 ListViewItem 的 MenuFlyout 绑定 Command: 在 ListView 的 事件中绑定所选择项目,即其 Sele ...

随机推荐

  1. RabbitMQ进程结构分析与性能调优

    RabbitMQ是一个流行的开源消息队列系统,是AMQP(高级消息队列协议)标准的实现,由以高性能.健壮.可伸缩性出名的Erlang语言开发,并继承了这些优点.业界有较多项目使用RabbitMQ,包括 ...

  2. Kali学习笔记42:SQL手工注入(4)

    前三篇文章都是在讲发现SQL注入漏洞 如何查询得到所有的信息 那么另一条思路还未尝试过:能否修改数据? 例如这样: '; update users set user='yiqing' where us ...

  3. [Swift]LeetCode397. 整数替换 | Integer Replacement

    Given a positive integer n and you can do operations as follow: If n is even, replace n with n/2. If ...

  4. [Swift]LeetCode519. 随机翻转矩阵 | Random Flip Matrix

    You are given the number of rows n_rows and number of columns n_cols of a 2D binary matrix where all ...

  5. [Swift]LeetCode886. 可能的二分法 | Possible Bipartition

    Given a set of N people (numbered 1, 2, ..., N), we would like to split everyone into two groups of  ...

  6. Java 11新功能抢先了解

    目前 Oracle 已经发布了 Java Development Kit 10,下个版本 JDK 11 也即将发布.本文介绍 Java 11 的新功能. 根据Oracle新出台的每6个月发布一次Jav ...

  7. [MV] - You Give REST a Bad Name

    本首歌改自Bon Jovi经典歌曲"You Give Love a Bad Name". 改编的作者是Dylan Beattie, 他是Spotlight的系统架构师. 改编后的歌 ...

  8. BBS论坛(十五)

    15.1.登录界面完成 (1)front/signbase.html {% from 'common/_macros.html' import static %} <!DOCTYPE html& ...

  9. log4cplus使用(二)-自定义日志等级

    log4cplus支持用户自定义日志等级,操作也比较简单,使用之前贴如下宏定义 #define LOG4CPLUS_MACRO_CREASH_LOG_LEVEL(pred) LOG4CPLUS_UNL ...

  10. influxdb使用说明

    前言 influxdb是目前比较流行的时间序列数据库. 何谓时间序列数据库?什么是时间序列数据库,最简单的定义就是数据格式里包含Timestamp字段的数据,比如某一时间环境的温度,CPU的使用率等. ...