IdentityMine

| Tags: Laurent Bugnion, Silverlight, WPF

originally posted by Laurent Bugnion: (link) - please comment at original post

Ever since I released V1.1 of the MVVM Light Toolkit, I have received wonderful and constructive feedback from users. Most of it is flowing into V2, which is almost ready (I am still fighting a little with MSI installers and project/item templates for one feature I am particularly happy about, which is making project templates and item templates available in Expression Blend. That’s right, with V2 you can start Blend, and choose “File / New Project / MVVM Light”, then press F5 to have an application running.

IMHO the most interesting and innovative change in the toolkit is the new Messenger. In V1.1, quite a lot of plumbing as involved to register for messages, and to send messages. You had to implement IMessageRecipient to get messages, and all messages had to inherit the MessageBase class. Let’s face it, this was a bad idea. Thankfully, Glenn Block (of MEF and Prism fame) called me on that, and suggested a much, much cleaner implementation: Get rid of IMessageRecipient and use Actions instead to register for messages. Get rid of MessageBase and allow me to send anything through the Messenger.

Binaries and code

The binaries and source code are available. Attention: It is a beta, so use it with care, and be prepared to upgrade to the final version in a few days.

The new API

This immediately appealed to me (and to some of my users whom I talked to) and I propose to you the Messenger V2. It implements the IMessenger interface, which should make mocking and testing easier. The interface looks like this:

01./// <summary>
02./// Registers a recipient for a type of message TMessage. The <see cref="action" />
03./// parameter will be executed when a corresponding message is sent.
04./// <para>Registering a recipient does not create a hard reference to it,
05./// so if this recipient is deleted, no memory leak is caused.</para>
06./// </summary>
07./// <typeparam name="TMessage">The type of message that the recipient registers
08./// for.</typeparam>
09./// <param name="recipient">The recipient that will receive the messages.</param>
10./// <param name="action">The action that will be executed when a message
11./// of type TMessage is sent.</param>
12.void Register<TMessage>(object recipient, Action<TMessage> action);
13.
14./// <summary>
15./// Registers a recipient for a type of message TMessage.
16./// The <see cref="action" /> parameter will be executed when a corresponding
17./// message is sent. See the <see cref="receiveDerivedMessagesToo" /> parameter
18./// for details on how messages deriving from TMessage (or, if TMessage is an interface,
19./// messages implementing TMessage) can be received too.
20./// <para>Registering a recipient does not create a hard reference to it,
21./// so if this recipient is deleted, no memory leak is caused.</para>
22./// </summary>
23./// <typeparam name="TMessage">The type of message that the recipient registers
24./// for.</typeparam>
25./// <param name="recipient">The recipient that will receive the messages.</param>
26./// <param name="receiveDerivedMessagesToo">If true, message types deriving from
27./// TMessage will also be transmitted to the recipient. For example, if a SendOrderMessage
28./// and an ExecuteOrderMessage derive from OrderMessage, registering for OrderMessage
29./// and setting receiveDerivedMessagesToo to true will send SendOrderMessage
30./// and ExecuteOrderMessage to the recipient that registered.
31./// <para>Also, if TMessage is an interface, message types implementing TMessage will also be
32./// transmitted to the recipient. For example, if a SendOrderMessage
33./// and an ExecuteOrderMessage implement IOrderMessage, registering for IOrderMessage
34./// and setting receiveDerivedMessagesToo to true will send SendOrderMessage
35./// and ExecuteOrderMessage to the recipient that registered.</para>
36./// </param>
37./// <param name="action">The action that will be executed when a message
38./// of type TMessage is sent.</param>
39.void Register<TMessage>(object recipient, bool receiveDerivedMessagesToo, Action<TMessage> action);
40.
41./// <summary>
42./// Sends a message to registered recipients. The message will
43./// reach all recipients that registered for this message type
44./// using one of the Register methods.
45./// </summary>
46./// <typeparam name="TMessage">The type of message that will be sent.</typeparam>
47./// <param name="message">The message to send to registered recipients.</param>
48.void Send<TMessage>(TMessage message);
49.
50./// <summary>
51./// Sends a message to registered recipients. The message will
52./// reach only recipients that registered for this message type
53./// using one of the Register methods, and that are
54./// of the targetType.
55./// </summary>
56./// <typeparam name="TMessage">The type of message that will be sent.</typeparam>
57./// <typeparam name="TTarget">The type of recipients that will receive
58./// the message. The message won't be sent to recipients of another type.</typeparam>
59./// <param name="message">The message to send to registered recipients.</param>
60.void Send<TMessage, TTarget>(TMessage message);
61.
62./// <summary>
63./// Unregisters a messager recipient completely. After this method
64./// is executed, the recipient will not receive any messages anymore.
65./// </summary>
66./// <param name="recipient">The recipient that must be unregistered.</param>
67.void Unregister(object recipient);
68.
69./// <summary>
70./// Unregisters a message recipient for a given type of messages only.
71./// After this method is executed, the recipient will not receive messages
72./// of type TMessage anymore, but will still receive other message types (if it
73./// registered for them previously).
74./// </summary>
75./// <typeparam name="TMessage">The type of messages that the recipient wants
76./// to unregister from.</typeparam>
77./// <param name="recipient">The recipient that must be unregistered.</param>
78.void Unregister<TMessage>(object recipient);
79.
80./// <summary>
81./// Unregisters a message recipient for a given type of messages and for
82./// a given action. Other message types will still be transmitted to the
83./// recipient (if it registered for them previously). Other actions that have
84./// been registered for the message type TMessage and for the given recipient (if
85./// available) will also remain available.
86./// </summary>
87./// <typeparam name="TMessage">The type of messages that the recipient wants
88./// to unregister from.</typeparam>
89./// <param name="recipient">The recipient that must be unregistered.</param>
90./// <param name="action">The action that must be unregistered for
91./// the recipient and for the message type TMessage.</param>
92.void Unregister<TMessage>(object recipient, Action<TMessage> action);

No Memory Leaks

One neat thing with the Messenger (already in V1 and of course also in V2) is that the objects are referenced using WeakReferences. Even though I recommend to unregister explicitly when you want to delete the message recipient, if you omit to do so, you won’t cause a memory leak, because the Messenger does not keep a hard reference to the recipient.

Backwards compatibility

All V1 methods are still available, but marked as Obsolete. This allows a smooth evolution of existing projects to the new syntax. When you build existing projects with the new toolkit, you will get warnings with a suggestion to move to the new syntax.

The MessageBase class and the deriving message types (GenericMessage, CommandMessage, CommandMessageGeneric, DialogMessage, PropertyChangedMessage) are still available as suggestions for the payload (i.e. you can use them if you like, but you can also build your own messages, or send anything you want (objects, simple value types, etc…). It is perfectly legal to do:

01.// Somewhere
02.Messenger.Default.Register<string>(this, DoSomething);
03.
04.// Further
05.private void DoSomething(string message)
06.{
07. // ...
08.}
09.
10.// Somewhere else
11.Messenger.Default.Send(“Hello world”);

Default Messenger, mocking, testing, IoC

Note that like in V1, you can either use the default Messenger (Messenger.Default) or create your own messengers, for example to create specialized channels of communication. Since the IMessenger interface is now available, you can easily mock, test, use IoC containers, etc…

The Messenger V2 as well as the rest of the toolkit will be available in a few days, and I will also prepare sample applications to demonstrate the use more in-depth.

Remember to please comment at original post: (link)

Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedInPin on PinterestShare on RedditShare on TumblrEmail this to someoneDigg thisFlattr the authorShare on StumbleUpon

Comments are closed.