77
88namespace Microsoft . Toolkit . Mvvm . Messaging
99{
10+ /// <summary>
11+ /// A <see langword="delegate"/> used to represent actions to invoke when a message is received.
12+ /// The recipient is given as an input argument to allow message registrations to avoid creating
13+ /// closures: if an instance method on a recipient needs to be invoked it is possible to just
14+ /// cast the recipient to the right type and then access the local method from that instance.
15+ /// </summary>
16+ /// <typeparam name="TRecipient">The type of recipient for the message.</typeparam>
17+ /// <typeparam name="TMessage">The type of message to receive.</typeparam>
18+ /// <param name="recipient">The recipient that is receiving the message.</param>
19+ /// <param name="message">The message being received.</param>
20+ public delegate void MessageHandler < in TRecipient , in TMessage > ( TRecipient recipient , TMessage message )
21+ where TRecipient : class
22+ where TMessage : class ;
23+
1024 /// <summary>
1125 /// An interface for a type providing the ability to exchange messages between different objects.
26+ /// This can be useful to decouple different modules of an application without having to keep strong
27+ /// references to types being referenced. It is also possible to send messages to specific channels, uniquely
28+ /// identified by a token, and to have different messengers in different sections of an applications.
29+ /// In order to use the <see cref="IMessenger"/> functionalities, first define a message type, like so:
30+ /// <code>
31+ /// public sealed class LoginCompletedMessage { }
32+ /// </code>
33+ /// Then, register your a recipient for this message:
34+ /// <code>
35+ /// Messenger.Default.Register<MyRecipientType, LoginCompletedMessage>(this, (r, m) =>
36+ /// {
37+ /// // Handle the message here...
38+ /// });
39+ /// </code>
40+ /// The message handler here is a lambda expression taking two parameters: the recipient and the message.
41+ /// This is done to avoid the allocations for the closures that would've been generated if the expression
42+ /// had captured the current instance. The recipient type parameter is used so that the recipient can be
43+ /// directly accessed within the handler without the need to manually perform type casts. This allows the
44+ /// code to be less verbose and more reliable, as all the checks are done just at build time. If the handler
45+ /// is defined within the same type as the recipient, it is also possible to directly access private members.
46+ /// This allows the message handler to be a static method, which enables the C# compiler to perform a number
47+ /// of additional memory optimizations (such as caching the delegate, avoiding unnecessary memory allocations).
48+ /// Finally, send a message when needed, like so:
49+ /// <code>
50+ /// Messenger.Default.Send<LoginCompletedMessage>();
51+ /// </code>
52+ /// Additionally, the method group syntax can also be used to specify the message handler
53+ /// to invoke when receiving a message, if a method with the right signature is available
54+ /// in the current scope. This is helpful to keep the registration and handling logic separate.
55+ /// Following up from the previous example, consider a class having this method:
56+ /// <code>
57+ /// private static void Receive(MyRecipientType recipient, LoginCompletedMessage message)
58+ /// {
59+ /// // Handle the message there
60+ /// }
61+ /// </code>
62+ /// The registration can then be performed in a single line like so:
63+ /// <code>
64+ /// Messenger.Default.Register(this, Receive);
65+ /// </code>
66+ /// The C# compiler will automatically convert that expression to a <see cref="MessageHandler{TRecipient,TMessage}"/> instance
67+ /// compatible with <see cref="IMessengerExtensions.Register{TRecipient,TMessage}(IMessenger,TRecipient,MessageHandler{TRecipient,TMessage})"/>.
68+ /// This will also work if multiple overloads of that method are available, each handling a different
69+ /// message type: the C# compiler will automatically pick the right one for the current message type.
70+ /// It is also possible to register message handlers explicitly using the <see cref="IRecipient{TMessage}"/> interface.
71+ /// To do so, the recipient just needs to implement the interface and then call the
72+ /// <see cref="IMessengerExtensions.RegisterAll(IMessenger,object)"/> extension, which will automatically register
73+ /// all the handlers that are declared by the recipient type. Registration for individual handlers is supported as well.
1274 /// </summary>
1375 public interface IMessenger
1476 {
@@ -28,13 +90,15 @@ bool IsRegistered<TMessage, TToken>(object recipient, TToken token)
2890 /// <summary>
2991 /// Registers a recipient for a given type of message.
3092 /// </summary>
93+ /// <typeparam name="TRecipient">The type of recipient for the message.</typeparam>
3194 /// <typeparam name="TMessage">The type of message to receive.</typeparam>
3295 /// <typeparam name="TToken">The type of token to use to pick the messages to receive.</typeparam>
3396 /// <param name="recipient">The recipient that will receive the messages.</param>
3497 /// <param name="token">A token used to determine the receiving channel to use.</param>
35- /// <param name="action ">The <see cref="Action{T }"/> to invoke when a message is received.</param>
98+ /// <param name="handler ">The <see cref="MessageHandler{TRecipient,TMessage }"/> to invoke when a message is received.</param>
3699 /// <exception cref="InvalidOperationException">Thrown when trying to register the same message twice.</exception>
37- void Register < TMessage , TToken > ( object recipient , TToken token , Action < TMessage > action )
100+ void Register < TRecipient , TMessage , TToken > ( TRecipient recipient , TToken token , MessageHandler < TRecipient , TMessage > handler )
101+ where TRecipient : class
38102 where TMessage : class
39103 where TToken : IEquatable < TToken > ;
40104
@@ -83,6 +147,14 @@ TMessage Send<TMessage, TToken>(TMessage message, TToken token)
83147 where TMessage : class
84148 where TToken : IEquatable < TToken > ;
85149
150+ /// <summary>
151+ /// Performs a cleanup on the current messenger.
152+ /// Invoking this method does not unregister any of the currently registered
153+ /// recipient, and it can be used to perform cleanup operations such as
154+ /// trimming the internal data structures of a messenger implementation.
155+ /// </summary>
156+ void Cleanup ( ) ;
157+
86158 /// <summary>
87159 /// Resets the <see cref="IMessenger"/> instance and unregisters all the existing recipients.
88160 /// </summary>
0 commit comments