User Tools

Site Tools


notes:csharp:mvvm_light

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
notes:csharp:mvvm_light [2017/04/19]
leszek [Messenger (Message Bus)]
notes:csharp:mvvm_light [2018/06/20]
leszek [Simple IoC]
Line 84: Line 84:
 =====Simple IoC===== =====Simple IoC=====
  
 +  * An IoC container allows us to provide an interface and receive an instance of a class that implements the provided interface. It's up to the container to figure out where to get that instance and how to return it back. 
 +  * An IoC container can also accept an instance of a class and then return this instance when we ask about the corresponding class type.
 +  * We can configure our IoC container at startup by registering all concrete types and interface we need in our application. It is called a //​composition root//. Often, you may have a separate bootstraper project to handle that.
 +  ​
   * When a class is registered, no instances are created.   * When a class is registered, no instances are created.
   * Object creation is on demand when the //​GetInstance//​ method is called the first time.   * Object creation is on demand when the //​GetInstance//​ method is called the first time.
Line 361: Line 365:
   * Pass the Messenger object to ViewModels explicitly. This makes the depenencies clear.   * Pass the Messenger object to ViewModels explicitly. This makes the depenencies clear.
   * Send messages of a certain type rather than generic messages. For example, InvoiceViewModel may send messages of type InvoiceMessage. Then, recipients register to listen for messages of type InvoiceMessage.   * Send messages of a certain type rather than generic messages. For example, InvoiceViewModel may send messages of type InvoiceMessage. Then, recipients register to listen for messages of type InvoiceMessage.
 +
 +  * Do not overuse the Messenger.
 +  * Use event handlers whenever possible and the Messenger as the last resort.
 +  * Sometimes the Messenger can be replaced by a service (a DialogService,​ a NavigationService,​ etc.)
 +  * Test your code for memory leaks.
 +  * If you are in doubt, unregister the messenger handling methods.
  
 Example: Register to listen for messages: Example: Register to listen for messages:
Line 419: Line 429:
 Example: Use a token to send and receive messages: Example: Use a token to send and receive messages:
 <code csharp> <code csharp>
-</code>+// Register and listen for messages. 
 +class MessageRecipient 
 +
 +    // The token has to be unique. It can be anything (a string, an instance of a custom class, etc.) 
 +    public static readonly Guid Token = Guid.NewGuid();​ 
 +    ... 
 +    Messenger.Default.Register<​NotificationMessage>(this, Token, HandleNotification);​ 
 +    ... 
 +    private void HandleNotification(NotificationMessage message) { /*...*/ } 
 +}
  
-  ​// A token is used to open private channel.+// Send message. Only the recipients who registered to listen for messages with the given token 
 +// will receive this message. 
 +Messenger.Default.Send(new NotificationMessage("​DoSomething"​),​ MessageRecipient.Token);
  
-  ​// Unregister ​using a token+// Unregister. 
-  Messenger.Default.Unregister<​IMessage>​(this,​ Token); +Messenger.Default.Unregister<​IMessage>​(this,​ Token); ​// all handlers 
-  Messenger.Default.Unregister<​IMessage>​(this,​ Token, HandleMessage);​ +Messenger.Default.Unregister<​IMessage>​(this,​ Token, HandleMessage);​ // a specific handler 
- +</code>
-- Sending with a token +
- +
- "​In this scenario, one or more recipients can register using a token in the Register method. The token can be anything (for example a Guid, a string, an instance of a custom object), it just has to be unique.  +
-  When the Sender sends a message using the same token, the Messenger filters who receives the message. For example, even if Recip2 registered for that message type,  +
-  because it didn't use the token, it will not receive the message. This prevents a need to write filtering logic in every recipient."​ +
- +
-    public class MessageRecipient +
-    { +
-        public static readonly Guid Token = Guid.NewGuid();​ +
- +
-        public MessageRecipient() +
-        { +
-            Messenger.Default.Register<​NotificationMessage>​(this,​ Token, HandleNotification);​ +
-        } +
- +
-        private void HandleNotification(NotificationMessage message) +
-        { +
-            ​// ... +
-        } +
-    } +
- +
-    public class MessageSender +
-    { +
-        public void SendMessage() +
-        { +
-            Messenger.Default.Send(new NotificationMessage("​DoSomething"​),​ MessageRecipient.Token);​ +
-        } +
-    } +
- +
-- Registering for base classes +
-  +
-  "​Another special case is possibility to register for an interface or a base class. For example, let's imagine an IMessage interface, implemented by a class called ImplementMessage. ​ +
-   If a recipient registers for a message of type IMessage and sets the bool flag to true (the second param of Messenger.Default.Register),​ then the method will be called when any message  +
-   ​implementing IMessage is sent. This is true when you send a message of type ImplementMessage,​ but it is also convenient with MyGenericMessage (--> slide), that can carry a payload of various types.  +
-   In this case, >>>​ the method will be called whatever the type of the payload is <<<.  +
-    +
-    Messenger.Default.Register<​IMessage>​(this,​ true, HandleMessage);​ +
-    private void HandleMessage(IMessagemessage) { }  +
- +
-    Messenger.Default.Send(new ImplementMessage());​ +
- +
-    Messenger.Default.Send(new MyGenericMessage<​string>​());​ +
- +
-- Dangers of Messenger +
-    - Do not overuse Messenger +
-    - Use event handlers whenever possible and the Messenger as the last resort +
-    - Sometimes the Messenger can be replaced by a service (a DialogService,​ a NavigationService,​ etc.) +
-    - Test your code for memory leaks +
-    - If you are in doubt, unregister the messenger handling method +
- +
-  "We will let some user controls communicate in a decoupled manner and demonstrate a OneWay message, as well as a message with feedback.  +
-   Here we have an MVVM application with a receiver and a sender ViewModel. Sender can send two kinds of messages:  +
-    +
-   1. LogMessage - it carries a Text and a Timestamp.  +
-   If we run the application,​ we notice the blue area, this is a SenderViewModel. There is a Send button and a text field. Let's enter a message and press the Send button.  +
-   ​Nothing happens because there is no receiver registered to get this message. In the ApplicationBar,​ there is an Add button. This adds a user control with a ReceiverViewModel as its data context.  +
-   If I press the Send button now, the message of type LogMessage is Send, because each of the ReceiverViewModel subscribed to this message type, we can see that those three user controls are getting it.  +
-   If we add a fourth user control and send the message again, we see that all four user controls get the message, but for the sender it doesn'​t make any difference.  +
-   In fact, if I remove all the receivers, and send the message again, nothing happens. The sender doesn'​t know that no one got the message.  +
-    +
-   2. LogMessageWithFeedback - Based on the LogMessage. It has a Feedback property, which is an Action<​bool>. We will use this action to send Feedback after the user has confirmed or cancelled the message.  +
-   ​Let'​s register a mix of receivers (e.g. LogMessage receivers and LogMessageWithFeedback receivers): the red ones listen to a LogMessage, the orange ones listen to a LogMessageWithFeedback.  +
-   ​Let'​s send a LogMessage. Here we see that only the red ones got it. If I send a LogMessageWithFeedback,​ the orange ones got it, but not the red ones.  +
-   Using the LogMessageWithFeedback,​ the user can send some Feedback to the sender. This will execute the Action of bool and the dialog is shown; for example, OK or Cancel.  +
-   Of course the parameter could be anything. Here I use the Boolean, but it could be a string or even a complex object type.  +
-    +
-   >>>​ SenderViewModel. We see what happens when a message needs to be sent (in SendCommand):​ +
-   - First, the LogMessage is constructed. +
-   - Then, we use Messenger.Default to Send the message.  +
-    +
-   in SendWithFeedbackCommand:​ +
-   - LogMessageWithFeedback accepts an Action which is going to be executed whenever the user wants to give some Feedback.  +
-     Here when the Action is executed, we will show a MessageDialog using the result to show the string "​OK"​ or "​Cancel"​.  +
-      +
-   >>>​ ReceiverViewModel - this is where we register for the type of message that we want to receiver, either LogMessageWithFeedback or LogMessage.  +
-    +
-   ​LogMessage:​ +
-   Like we saw in the slide, the Receiver method needs a reference to the receiver itself in order to monitor the lifetime, and a delegate to the method which will be executed. +
-   In this merthod we build a string with the parameters from the message (Text and Timestamp) and then we assign this to the Display property, which is data bound in XAML.  +
-    +
-   ​LogMessageWithFeedback:​ +
-   In the case of the Feedback message, we also save the message.Feedback property, which is an Action, to execute it later.  +
-    +
-   ​SendFeedbackCommand - executes (calls) the Feedback delegate.  +
-   This command is bound in XAML to the OK and the Cancel buttons. You can see that we simply execute the _feedback action and pass a Boolean.  +
-    +
-   ​Unload - unregisters the two message types +
-   For simplicity, we simply unregister everything when the user control is unloaded. This is not strictly necessary, because in Windows 8 even private methods  +
-   can be saved with a weak reference, and the receiver can be garbage collected but it is always a good policy to cleanly unregister whenever possible.+
  
 =====ViewModelLocator===== =====ViewModelLocator=====
notes/csharp/mvvm_light.txt · Last modified: 2018/06/20 by leszek