你的位置:首页 > ASP.net教程

[ASP.net教程]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添加喝彩。