Silverlight, MEF and Messaging - Sending but not receiving...

Aug 10, 2011 at 10:07 PM

I'm having a heck of a time to get messaging to work properly in my app.  Is there something special that needs to be addressed with Silverlight and/or MEF?

I'm adding my Messenger.Default.Register code in a constructor for a ViewModel and then calling some Messenger.Default.Send code in a different ViewModel using a command.  The command will fire and pass the proper parameters and it appears the Send code is executing, however it doesn't appear that the "recieve" ViewModel is really ever being constructed and thus the Register code is never called.  Is there another convention I should be following for registering messages when using MEF?!?!

Coordinator
Aug 10, 2011 at 10:18 PM

Hi,

MEF and Messenger work well together, in fact one of the main value of the Messenger is scenarios like MEF where plugins get loaded at various times.

However there is a catch: the message will only get received if the recipient is registered already. With that, I mean that the delivery is immediate, there is no delayed delivery (yet.... more about this in V5 later...).

Make sure that your recipient VM gets constructed by MEF, registers properly and then you will start receiving the messages.

Makes sense?

Cheers,

Laurent

Aug 12, 2011 at 5:30 PM
Edited Aug 12, 2011 at 5:45 PM

Makes perfect sense...implemented a "message queue" so to speak which seems to work pretty well.  If you (or anyone) notices anything that could be improved, greatly appreciated!

Here is the command:


     private RelayCommand<string> _viewDetailCommand = null;
     public RelayCommand<string> ViewDetailCommand
     {
          get
          {
               if (_viewDetailCommand == null)
                    _viewDetailCommand = new RelayCommand<string>(
                         p =>
                         {
                              AppMessages.ViewDetailMessage.QueueMessageAndNavigate(p, ViewTypes.DetailView);
                         });
               return _viewDetailCommand;
          }
     }

Then in the ctor of the ViewModel I've navigated to I call this:

 

AppMessages.ViewDetailMessage.Register(this, OnViewDetail);
AppMessages.MessageQueue.Instance.ReleaseMessagesFromQueue<AppMessages.ViewDetailMessage>();

 

Here is the message and an interface to facilitate the "delayed" execution of the Send until after the ViewModel is loaded:

     public interface IQueueableMessage
     {
          void ReleaseFromQueue();
     }

     public class ViewDetailMessage : AppMessageBase, IQueueableMessage
     {
          private string recordNumber { get; set; }
            
          public ViewDetailMessage() : base(MessageTypes.ViewDetail) { }

          public static void QueueMessageAndNavigate(string recordNumber, string viewType)
          {
               ViewDetailMessage _msg = new ViewDetailMessage();
               _msg.recordNumber = recordNumber;
               MessageQueue.Instance.AddMessageToQueue(_msg);

               NavigateMessage.Send(viewType);
          }
          public static void Register(object recipient, Action<string> action)
          {
               Messenger.Default.Register<string>(recipient, MessageTypes.ViewDetail, action);
          }
          public static void Send(string recordNumber)
          {
               Messenger.Default.Send<string>(recordNumber, MessageTypes.ViewDetail);
          }
          public void ReleaseFromQueue()
          {
               ViewDetailMessage.Send(this.recordNumber);
          }
     }

...and finally here is the MessageQueue code:

     public sealed class MessageQueue
     {
          private List<IQueueableMessage> Queue = new List<IQueueableMessage>();

          private static readonly MessageQueue _instance = new MessageQueue();

          public static MessageQueue Instance
          {
               get
               {
                    return _instance;
               }
          }

          private MessageQueue() { }

          public void AddMessageToQueue<T>(T msg) where T : IQueueableMessage
          {
               this.Queue.Add(msg);
          }

          public void ReleaseMessagesFromQueue<T>() where T : IQueueableMessage
          {
               this.Queue.OfType<T>().ToList().ForEach(
                    m => {
                         m.ReleaseFromQueue();
                         this.Queue.Remove(m);
               });
          }
     }