Click here to Skip to main content
15,887,404 members
Articles / Programming Languages / C#
Technical Blog

Thinking in MVVMLight Messenger

Rate me:
Please Sign up or sign in to vote.
4.67/5 (3 votes)
14 Dec 2013CPOL6 min read 13.4K   9  
How to think in MVVMLight messenger

Introduction

MVVM Light is a good MVVM design pattern library for .NET developers. For me, the main use of a messenger is because it allows for communication between ViewModels. Let's say, you have a viewmodel that is used to provide business logic to a search function and 3 viewmodels on your page/window that want to process the search to show output, the messenger would be the ideal way to do this in a loosely-bound way. A question from stackoverflow.com has answered perfectly why and when we use MVVM Light messenger (The answer of the question is PSed at the end of this article). See examples of Laurent Bugnion’s web site to learn how to use MVVM Light messenger.

In fact, this article will be useful for myself so that I should really master Mediator Design Pattern. So I’ll write here my comprehension of Laurent Bugnion’s code for Messenger.

The code source of part Messenger of MVVM Light is in GalaSoft.MvvmLight (NET35) package. It seems that the later version of MvvmLight doesn’t change Messenger’s code.

  • C#
    void Register<TMessage>(object recipient, 
    object token, bool receiveDerivedMessagesToo, Action<TMessage> action); 
  • C#
    void Send<TMessage>(TMessage message, object token); 

These are two most often used functions in my projects. Register registers a recipient for a type of message TMessage. The action parameter will be executed when a corresponding message is sent. Registering a recipient does not create a hard reference to it, so if this recipient is deleted, no memory leak is caused.

Take a look at implementation of register function. In the case which doesn’t receive derived messages, a variable type of Dictionary<Type, List<WeakActionAndToken>> is there : recipients, which is the reference of a local variable _recipientStrictAction. Variable recipients is locked, because it references a very important local variable which records all registered types in the messenger system. If entered TMessage type didn't exist in recipients list, then add it into the list.

Each type of TMessage contains a list of WeakActionAndToken which contains one WeakAction and one Token.

C#
private struct WeakActionAndToken
{
    public WeakAction Action;
    public object Token;
}

Send sends a message to registered recipients. The message will reach only recipients that registered for this message type using one of the Register methods, and that are of the targetType.

C#
public virtual void Send<TMessage>(TMessage message, object token)
{
    SendToTargetOrType(message, null, token);
}

In the code, it searches in the list of recipients until it finds the same type of TMessage. It takes all lists of WeakActionAndToken of a recipient. Here, we set messageTargetType to null.

C#
private static void SendToList<TMessage>(TMessage message, 
IEnumerable<WeakActionAndToken> weakActionsAndTokens, Type messageTargetType, object token)

In the function SendToList, we get TMessage’s WeakActionAndToken list. For each item in the WeakActionAndToken list, it has a Token and a WeakAction object. For example, we have two classes A and B, class A wants to receive messages from B. We need to create a common TMessage for transferring message from B to A, we call it MessageBToA (it is a class).

A creates a receiver for receiving B’s message, so A registers a TMessage of type MessageBToA into the list of _recipientsStrictAction. So in the MVVM Light’s messenger system of program conserves a message : MessageBToA -> List<WeakActionAndToken> { [WeakAction { recipient = object A, action = Action<MessageBToA>}, Token = static object ] }.

B is ready for sending a message to A. But if B didn’t get a object of A, what should B do then? B sends a cast message to all targets which is registered in the MessageBToA message system.

Now we analyse function SendToList. In _recipientsStrictAction, B searches item which type is MessageBToA. B found that there is a item of type MessageBToA. There is only one item in the list of WeakActionAndToken of type MessageBToA, B has a good token to access this item. B doesn’t care to whom the message will be sent, he just wants to send its message to A (whatever anyone else can receive it), so the program invokes registered Action<MessageBoToA> created by A with B’s message content.

Messenger

Technically, the messenger system is realized with using Action<T>. Receiver created an Action<TMessage> and affects a implementation of method of this action. Sender get this Action<TMessage> and gives TMessage a real instance to be the parameter of this action. We just need to get this action’s MethodInfo and invoke it. Once the method is invoked, the function which is already attached will be executed.

C#
public class WeakAction
{
    ...
    public void Execute()
    {
        ...
        Method.Invoke(actionTarget, null);
        ...
    }
}
At last, there is one thing that is very important, it is that for maintaining these registered messengers, Messenger class has to be a singleton class.

——————————————————————————————————————————————–

P.S.: Proper way of using MVVM Light Messenger (Ref from stackoverflow.com)

For me, the main use of a messenger is because it allows for communication between viewModels. Let's say you have a viewmodel that is used to provide business logic to a search function and 3 viewmodels on your page/window that want to process the search to show output, the messenger would be the ideal way to do this in a loosely-bound way.

The viewmodel that gets the search data would simply send a “search” message that would be consumed by anything that was currently registered to consume the message.

The benefits here are:

  1. Easy communication between viewmodels without each viewmodel having to know about each other.
  2. I can swap out the producer without affecting a consumer.
  3. I can add more message consumers with little effort.
  4. It keeps the viewmodels simple.

Edit: So, what about services?

ViewModels are all about how to present data to the UI. They take your data and shape it into something that can be presented to your View. ViewModels get their data from services.

A service provides the data and/or business logic to the ViewModel. The services job is to service business model requests. If a service needs to communicate/use other services to do its job, these should be injected into the service using dependency injection. Services would not normally communicate with each other using a messenger. The messenger is very much about horizontal communication at the viewmodel level.

One thing I have seen done is to use a messenger as a mediator(mediator description ), where instead of injecting the service directly into a viewmodel, the messenger is injected into the viewmodel instead. The viewmodel subscribes to an event and receives events containing models from the event. This is great if you’re receiving a steady flow of updates or you’re receiving updates from multiple services that you want to merge into a single stream.

Using a messenger instead of injecting a service when you’re doing request/response type requests doesn’t make any sense as you’ll have to write more code to do this that you’d have to write just injecting the service directly and it makes the code hard to read.

Looking at your code, above, imagine if you had to write an event for each method on there (Navigate, CanNavigate, GoBack, GoForward, etc.). You’d end up with a lot of messages. Your code would also be harder to follow.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
France France
A foolish 18 years old boy
Just got an Microsoft C# Specialist Certification. Objectif of this year : MCSD

Comments and Discussions

 
-- There are no messages in this forum --