Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Implement a Simple Messenger for MVVM User Controls and Apps

DZone's Guide to

Implement a Simple Messenger for MVVM User Controls and Apps

Learn more about implementing a Singleton class that will listen for changed values, creating a messenger.

· Integration Zone
Free Resource

Modernize your application architectures with microservices and APIs with best practices from this free virtual summit series. Brought to you in partnership with CA Technologies.

User controls are awesome. You put together a simple to use (in the best case, that is) component to reuse in your project(s). Sometimes, you even put that control into a (portable) class library to make it available across platforms. Most user controls are written without MVVM, using just DependencyProperties and the matching code behind file.

But – it is possible to create a user control that comes with its own ViewModel, keeping only the DependencyProperties in code behind. There are some limits when it comes to values that are generated by the view of your control. You can’t get them into your ViewModel without creating a reference to it (which may break the MVVM pattern in some eyes). Well, some will argue “who cares, I need to get this working, so I am getting a reference to the DataContext." This is ok, but there is also another, in my opinion more elegant solution. A class that listens for those changed values, pulling them into your ViewModel – a so called messenger.

Some of you might have used a Framework/Toolkit like MVVMLight, Prism, or similar. If you want to use them in a class library, you will find some stones in your way like a missing ViewModelLocator and more. At work, I am working on a universal user control for our LOB applications. Since the control involves a lot of values from its view, I needed a smart and fast way to get those into my ViewModel. I achieved it with my own simple messenger, enabling me to avoid any Framework/Toolkit in my control.

Here is how I did it. First I created a new Singleton class. If you do not know what a Singleton is, just click on the link in the sentence before. Long story short: a Singleton makes the class static, and makes sure that there is only one instance that all other classes are working with (to ultimately get the correct values). Hint: it may happen that due to some bad timing, you are still having more than one instance. In this case, you should have a look into a different way of implementation the call to the Singleton instance.

In my case, I am using the simple implementation, which automatically creates the first instance if there is none:

    public class SimpleMessenger
    {
        private static SimpleMessenger _instance;

        public static SimpleMessenger Instance => _instance ?? (_instance = new SimpleMessenger());
     }

The next step is to create an EventHandler, that informs us when the SimpleMessenger has new values. It makes absolutely sense to create your own EventArgs to be passed into the EventHandler. Just collect the data that you want to provide in a class that derives from EventArgs, and make the EventHandler using this class as its event data:

        //declaring EventHandler
        public event EventHandler<MessageValueChangedEventArgs> MessageValueChanged;


        //custom event args class
        public class MessageValueChangedEventArgs : EventArgs
        {

            public string PropertyName { get; set; }

            public object OldValue { get; set; }

            public object NewValue { get; set; }
        }

The most important function in this class is to raise the event:

        //raising the event for a property
        public void RaiseMessageValueChanged(string propertyName, object oldValue, object value)
        {
            MessageValueChanged?.Invoke(this, new MessageValueChangedEventArgs() { PropertyName = propertyName, NewValue = value, OldValue = oldValue });
        }

I am using just three basic values that are needed: the name of the property that changed, its old and its updated value. This already enables me to send data between View and ViewModel, or even to outside of my control. Of course, you want to see how one does send “messages” with my SimpleMessenger. It’s pretty simple, too.

First, you need to get a reference to the current instance:

        private SimpleMessenger _simpleMessenger;

        public MainPage()
        {
            this.InitializeComponent();

            _simpleMessenger = SimpleMessenger.Instance;
         }

To send data, just use the RaiseMessageValueChanged event:

_simpleMessenger.RaiseMessageValueChanged("RootGridSize", e.PreviousSize, e.NewSize);

Last but not least, we are also able to read those values in some other place:

        private SimpleMessenger _simpleMessenger;

        public MainViewModel()
        {
            _simpleMessenger = SimpleMessenger.Instance;
            _simpleMessenger.MessageValueChanged += OnSimpleMessengerValueChanged;
        }

        private void OnSimpleMessengerValueChanged(object sender, SimpleMessenger.MessageValueChangedEventArgs e)
        {
            if (e.PropertyName == "RootGridSize")
            {
                var size = (Size)e.NewValue;

                Debug.WriteLine($"Current Size: {size.Height}x{size.Width}");
            }

        }

As you can see, it is simple to use this class to get values in decoupled way (like the MVVM pattern requires). Of course, you still have to take care not to overuse this. I am using it for example to get the changed values of DependencyProperties that my control has into the ViewModel (which would otherwise only be possible with a reference to it).

This SimpleMessenger may not be as powerful as those in the popular Frameworks/Toolkits, but for usage in user controls or small apps it should fit in perfect.  I attached a very simple project to demonstrate the SimpleMessenger. Just start the project, and use your mouse to resize the app window. It will write the Size of the root grid to the console.

Download sample

As always, I hope this post is helpful for some of you.

The Integration Zone is proudly sponsored by CA Technologies. Learn from expert microservices and API presentations at the Modernizing Application Architectures Virtual Summit Series.

Topics:
messaging ,mvvm ,singleton ,integration

Published at DZone with permission of Marco Siccardi, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}