A lap around the Microsoft MVVM Toolkit

In this article we’ll walk through a UWP sample app to experiment with the features of the new Microsoft.Toolkit.Mvvm package that is part of the Microsoft Community Toolkit.

MVVM

MVVM is a software architectural pattern introduced by Microsoft in 2005 to support the development of XAML apps, originally in WPF and later on in Silverlight. MVVM stays relevant to the more recent XAML environments such as UWP, Xamarin (MAUI), the Uno platform, and WinUI.

In a nutshell MVVM allows you to separate UI logic from business logic by dividing your code into

  • Models that represent data or information – think ‘domain objects’ or ‘entities’,
  • Views that represent the structure and layout that the user interacts with – think ‘pages’ and ‘controls’, and
  • ViewModels that express Model data and business logic through methods, properties and commands that are accessible to the Views,  preferably via declarative data-binding.

MVVMCore

MVVM requires the strong data-binding capabilities that we see in XAML through its {Binding} and {x:Bind} markup extensions. The pattern was also implemented in other technology stacks such as AngularJS/Angular.io, Ext JS and Vue.js.

Microsoft started recommending MVVM for XAML 15 years ago and they still do. Oddly enough, they only provided ‘bindable controls’ and never came up with official helper classes (like base classes that implement INotifyPropertyChanged or ICommand) or an MVVM development framework (with event aggregation, messaging, or viewmodel location). The only exception is the Composite Application Library, which later grew into Prism. Regarding MVVM, Microsoft developers always had to rely on (Open Source) third parties, of which the most popular (in alphabetical order) are/were Caliburn, MVVM Light, and Prism.

We had great experiences with each of these frameworks. However -except for Prism- none of them are still actively maintained. We assume that the ecosystem for XAML apps is evolving too rapidly for the maintainers of larger Open Source libraries. Indeed none of the existing MVVM frameworks was ever designed with .NET Core, Uno, MAUI or WinUI 3 in mind…

Maybe it’s time for a new wind to blow.

Enter Windows MVVM Toolkit

The Microsoft.Toolkit.Mvvm package is a modern, fast, and modular MVVM library that is part of the Windows Community Toolkit (WCT). The package targets .NET Standard 2.* so it can be used on

  • any .NET app platform: UWP, WinForms, WPF, Xamarin, Uno, WinUI and more, and on
  • any .NET runtime: .NET Native, .NET Core, .NET Framework, or Mono.

Its API surface is the same in all environments, making it perfect for building shared libraries.

The object model and terminology are definitely inspired by MVVM Light and the development team is aiming to provide a smooth migration path from MVVM Light to the new toolkit. Apart from functionality WCT Toolkit also pays high attention to performance. Many benchmarks like this one (on the Messenger class) are continuously run during the development:

perf2

The package comes with documentation and a nice sample app. WCT MVVM is currently in ‘preview 4’ so everything is still work in progress.

A UWP Sample App

A few months ago this GitHub issue revealed the initial feature set of Microsoft MVVM Toolkit, preliminary documentation, and even an operational preview package. We decided to create a little UWP app to test that package. Here’s how the home page looks like – standard clean WinUI 2.5:

HomePage

We’ll use this app throughout this article to explore the features of the new MVVM Toolkit in town.

Core classes

The Building Blocks page of the sample app illustrates the core classes for data binding and commanding:

BuildingblocksPage

ObservableObject

ObservableObject provides a base class for types to implement INotifyPropertyChanged and INotifyPropertyChanging – typically Models and ViewModels. You may have encountered similar helpers in other frameworks under the name ObservableBase, BindableBase, or NotifyPropertyChanged. Typically such a class comes with an easy way to raise the PropertyChanged event in property Setters, and that’s exactly what SetProperty() does.

Here’s what it looks like in one of our Model classes:

public class SuperHero : ObservableObject
{
    private string _name;

    public string Name
    {
        get => _name;
        set => SetProperty(ref _name, value);
    }

    // ...
}

Here’s another example from the sample app, this time for a ViewModel – the one that is bound to the BuildingBlocksPage View:

public class BuildingBlocksPageViewModel : ObservableObject
{
    private SuperHero _superHero;

    public SuperHero SuperHero
    {
        get => _superHero;
        set => SetProperty(ref _superHero, value);
    }

    // ...

}

Here’s how the ViewModel is declaratively bound to the View as its DataContext:

<Page.DataContext>
    <viewModels:BuildingBlocksPageViewModel x:Name="ViewModel" />
</Page.DataContext>

When we change a property on the SuperHero, the UI will update:

ViewModel.SuperHero.Nemesis = _nemeses[rnd.Next(0, 5)];

When the property that you want to monitor is a Task<T>, then you can use SetPropertyAndNotifyOnCompletion() instead of SetProperty(). It wil set the property but with the help of an internal TaskNotifier<T> it will delay the notification to when the task was completed:

private TaskNotifier<string> _saveTheUniverseTask;

public Task<string> SaveTheUniverseTask
{
    get => _saveTheUniverseTask;
    private set
    {
        SetPropertyAndNotifyOnCompletion(ref _saveTheUniverseTask, value);
    }
}

There’s even an overload that allows you to register a callback for when the task finishes. Here’s the ViewModel code triggered by the save button on the sample page. It assigns a new value to the task, and then starts it:

public async Task SaveTheUniverse()
{
    SaveTheUniverseTask = new Task<string>(
        () =>
        {
            Task.Delay(2000).Wait();

            if (rnd.Next(2) > 0)
            {
                return $"We're doomed, I lost my {SuperHero.Tool}.";
            }

            return "We're saved ... this time.";
        }
    );

    _saveTheUniverseTask.Start();
}

The task was made observable, so you can monitor its status and result. A simple binding suffices to follow up on the Status [note: The sample app has some extra code to reveal more statuses than ‘initial’ and ‘completed’.]:

<Run Text="{x:Bind ViewModel.SaveTheUniverseTask.Status, Mode=OneWay}" />

We needed to add some extra code to bind to the Result of the task, since UWP XAML does not allow you to bind to a generic. Here’s a ‘wrapper’ property for the result:

public string SaveTheUniverseTaskResult => 
	_saveTheUniverseTask.Status == TaskStatus.RanToCompletion 
	? _saveTheUniverseTask.Result 
	: "(hold your breath)";

And again, the declarative binding:

<Run Text="{x:Bind ViewModel.SaveTheUniverseTaskResult, Mode=OneWay}" />

RelayCommand

The RelayCommand class – a.k.a. DelegateCommand in some frameworks- and its generic and asynchronous siblings provide a default implementation of the ICommand interface. It’s used to declaratively bind events in UI controls to methods in the viewmodel. In the sample app the BuildingBlocksPageViewModel has the following method to toggle its data provider:

private void SwitchDataProvider()
{
    if (_dataProvider is RedDataProvider)
    {
        DataProvider = new BlueDataProvider();
    }
    else
    {
        DataProvider = new RedDataProvider();
    }

    SuperHero = _dataProvider.SuperHero();
}

To trigger this method from a button, we declare a property of the ICommand type:

public ICommand SwitchDataProviderCommand { get; }

Then we let a RelayCommand refer to it:

SwitchDataProviderCommand = new RelayCommand(SwitchDataProvider);

In the view we can now bind the button’s Command property to the ViewModel’s property of type ICommand:

<Button Command="{x:Bind ViewModel.SwitchDataProviderCommand}" />

AsyncRelayCommand extends the ICommand behavior with support for asynchronous operations. Here’s an example of an asynchronous data provider switch:

private async Task SwitchDataProviderAsync()
{
    await Task.Delay(1000);

    SwitchDataProvider();
}

The corresponding property is defined as IAsyncRelayCommand:

public IAsyncRelayCommand SwitchDataProviderAsyncCommand { get; }

And assigned to an AsyncRelayCommand instance:

SwitchDataProviderAsyncCommand = new AsyncRelayCommand(SwitchDataProviderAsync);

IAsyncRelayCommand inherits from ICommand, so you can bind it to a Button’s Command:

<Button Command="{x:Bind ViewModel.SwitchDataProviderAsyncCommand}" />

The ExecutionTask property gives you access to the underlying Task, so you can monitor it. There’s also a convenient IsRunning property that indicates when the task is … running. You can use this to display a busy indicator, such as a ProgressRing. Here’s how such binding looks like:

<winui:ProgressRing
   IsActive="{x:Bind 
	ViewModel.SwitchDataProviderAsyncCommand.IsRunning, 
	FallbackValue=False, 
	Mode=OneWay}" />

ObservableValidator

ObservableValidator is an ObservableObject that hosts a default implementation of INotifyDataErrorInfo. This enables Models and ViewModels to implement validation rules and expose validation results. INotifyDataErrorInfo used to be an important interface some years ago, when all out-of-the-box controls in e.g. Windows Forms, ASP.NET Forms, and WPF came with error templates that implemented the UI part of this interface. It looks like the built-in class comments in the validation annotation attributes are still living in that era – not really reassuring for today’s .NET Client developers:

RegexValidator

In the modern XAML stacks you need to do all of the control templating manually or rely on a third-party control library. But here’s the good news: rumor has it that WinUI 3 will bring back error templates for XAML controls, so we welcome this WCT MVVM Toolkit’s ObservableValidator very much.

The ObservableValidator class comes with

  • members that implement the INotifyDataErrorInfo interface (HasErrors, GetErrors(), ErrorsChanged, …), 
  • overloads of SetProperty() that allow you to specify whether or not validation should run on the assignment of a new property value,
  • a TrySetProperty() that does not assign the value if it induces validation errors, and 
  • support for all kinds of validation attributes from the System.Component.DataAnnotations namespace.

Here’s the StudyGroup class from our sample app. Its properties are decorated with validation rules on requirement, length, numerical range, and regular expression pattern:

public class StudyGroup : ObservableValidator
{
    [Required(ErrorMessage = "Topic is Required")]
    [MinLength(2, ErrorMessage = "Topic should be longer than one character")]
    public string Topic
    {
        get => _topic;
        set => SetProperty(ref _topic, value, true);
    }

    [Range(2009, 2015, ErrorMessage = "Class should be from 2009 to 2015")]
    public int Class
    {
        get => _class;
        set => SetProperty(ref _class, value, true);
    }

    [RegularExpression(@".*[pP]aintball.*", ErrorMessage = "Hobbies should contain 'Paintball'.")]
    public string Hobbies
    {
        get => _hobbies;
        set => SetProperty(ref _hobbies, value, true);
    }

    // ...
}

Many more validation attributes exist. Some allow you to compare the new value of a property to the old one, or compare the value of two properties within the instance. It’s also very easy to roll your own custom validation attribute.

Using the INotifyDataErrorInfo members a View can react appropriately to the the validation state of its ViewModels. In our sample app we decided to let StudyGroup expose an Errors string with the concatenated list of validation errors. A symbol icon with a tooltip displays the messages:

<SymbolIcon Symbol="ReportHacked"
            Foreground="Red"
            Visibility="{x:Bind ViewModel.StudyGroup.HasErrors, Mode=OneWay}"
            HorizontalAlignment="Right"
            Margin="0 4">
    <ToolTipService.ToolTip>
        <TextBlock Text="{x:Bind ViewModel.StudyGroup.Errors, Mode=OneWay}"
                    Foreground="Red" />
    </ToolTipService.ToolTip>
</SymbolIcon>

Here’s how it looks like in action:

Validation

Messaging

In an MVVM application, ViewModels as well as other components may need to communicate with each other in a loosely coupled way. Most MVVM libraries have a Messenger infrastructure for this purpose.

MVVMMessenger

Microsoft MVVM Toolkit’s messaging API allows independent modules to exchange information via messages through a publish/subscribe mechanism. Our sample app hosts two scenario’s. Both scenario’s have different View/ViewModel pairs (a.k.a. “Modules”) on the same page. They are unaware of each other, but need to exchange information about the current ‘theme’.

Here’s the first messaging scenario:

  • the ViewModel of the Shell hosts the current ‘Theme’ (just a color),
  • when the sample page opens, all modules request the current theme and adapt their UI,
  • a ‘Theme Module’ allows to update this current theme through a ToggleSwitch,
  • the other modules update their UI immediately, and
  • the ‘Theme’ is not a global variable (and neither is the ShellViewModel).

Here’s how the page looks like:

MessengerPage

Messages

In this scenario we use two of the message base classes that come with MVVM Toolkit. Here’s the definition of the message that is sent by the theme module when the theme changed, a ValueChangedMessage<T>:

public class ThemeChangedMessage : ValueChangedMessage<Theme>
{
    public ThemeChangedMessage(Theme value) : base(value)
    {
    }
}

Here’s the definition of the message that all modules use to get the current theme, a RequestMessage<T>:

public class ThemeRequestMessage : RequestMessage<Theme>
{
}

ObservableRecipient and Messenger

All ViewModels in this scenario inherit from ObservableRecipient  (which was called ViewModelBase in Preview 1) to get access to an IMessenger instance via the Messenger property.

Here’s the ShellViewModel from our sample app. It switches to the default theme, and starts listening for the ThemeRequestMessage (which it answers with the theme) and the ThemeChangedMessage (which updates the theme). In a production app, the theme would probably be persisted in the Settings.

Here’s the definition of the ShellViewModel:

public class ShellViewModel : ObservableRecipient
{
    private Theme _theme = Theme.Default;

    public ShellViewModel()
    {
        Messenger.Register<ThemeRequestMessage>(this, m =>
        {
            m.Reply(_theme); 
        });

        Messenger.Register<ThemeChangedMessage>(this, m =>
        {
            _theme = m.Value;
        });
    }
}

Here’s the call that the theme-aware modules make to fetch the current theme when they are displayed:

_theme = Messenger.Send<ThemeRequestMessage>();

Just like the ShellViewModel they also subscribe to the ThemeChangedMessage to update:

Messenger.Register<ThemeChangedMessage>(this, m =>
   {
      // ...
   }

Sending a message is as easy as calling Send() on the Messenger:

Messenger.Send(new ThemeChangedMessage(_theme));

Under the hood, the messaging infrastructure is using classic .NET Events and Delegates. It’s important that ViewModels unsubscribe their callbacks when they stop listening for messages. The IMessenger interface comes with several Unregister() members, of which this one is the most radical:

Messenger.UnregisterAll(this);

Generally a ViewModel should only send messages and respond to messages when it is in an operational state – i.e. when it is bound to a loaded View. This operational state can be defined with the IsActive property. When the property becomes true, the OnActivated() method is called, so that’s the appropriate place to register your callbacks:

protected override void OnActivated()
{
    base.OnActivated();

    Messenger.Register<ThemeChangedMessage>(this, m =>
    {
        // ...
    });
}

When IsActive becomes false, OnDeactivated() is called. Its default implementation unregisters all callbacks, so in most cases you need to do … nothing.

Here’s how a View in the sample app marks out the operational state of its ViewModel:

private void ColorModule_Loaded(object sender, RoutedEventArgs e)
{
    _colorModuleViewModel.IsActive = true;
}

private void ColorModule_Unloaded(object sender, RoutedEventArgs e)
{
    _colorModuleViewModel.IsActive = false;
}

The default Messenger in the current version of WCT MVVM uses WeakReferences under the hood, so dangling ViewModels with non-unregistered callbacks will eventually be cleaned up by the Garbage Collector. If you’re sure that your app nicely unregisters all messaging handlers, then you may switch to the original (faster!) Messenger that relies on strong references. Here’s how to do this:

public class ShellViewModel : ObservableRecipient
{
    public ShellViewModel() : base(StrongReferenceMessenger.Default)
    {}

    // ...

}

Message Tokens

Some apps may host groups of modules that listen to different variations of messages. Message tokens can be very useful to reduce the communication overhead. Here’s a screenshot of our sample app – the page is based of a real-life scenario and shows four modules:

  • one that broadcasts all pillow-and-blanket war casualties,
  • one that is only interested in pillow victims,
  • one that is only interested in blanket victims, and
  • one that is interested in all casualty messages.

MessengerWithTokenPage

The message itself is empty – it’s good to see that no specific base class is needed:

public class CasualtyMessage // No specific base class needed.
{
}

When a casualty is reported, the broadcast module sends the message, and uses the victim’s party (pillow or blanket) as token:

Messenger.Default.Send<CasualtyMessage, string>(new CasualtyMessage(), "pillow");
// OR
Messenger.Default.Send<CasualtyMessage, string>(new CasualtyMessage(), "blanket");

The next to modules register a callback for CasualtyMessage, but only for their own token:

Messenger.Register<CasualtyMessage, string>(this, "blanket", m => { OnCasualtyMessageReceived(); });

The fourth module registers twice, once for each token. It’s impossible to receive tokenized messages without tokenized registration. So in out sample app, the following will not receive a single message:

// Does not see the messages with a token.
Messenger.Register<CasualtyMessage>(this, m => { OnCasualtyMessageReceived(); });

In our sample app –and many other- Enumations would make an ideal candidate for tokens. After all: the use of hardcoded strings is risky business. Unfortunately token classes are required to implement IEquatable<T> as you see in the definition:

void Register<TMessage, TToken>(object recipient, TToken token, Action<TMessage> action)
            where TMessage : class
            where TToken : IEquatable<TToken>;

This constraint rules out the use of Enumerations. So we created the Party class that looks and feels like an Enum, but implements the interface:

public sealed class Party : IEquatable<Party>
{
    public static readonly Party Pillow = new Party(1, nameof(Pillow));
    public static readonly Party Blanket = new Party(2, nameof(Blanket));

    public string Name { get; private set; }

    public int Id { get; private set; }

    private Party(int id, string name)
    {
        Id = id;
        Name = name;
    }

    public bool Equals(Party other)
    {
        return Id == other.Id;
    }
}

The class can be used as token, instead of String, and we ended up with a much better maintainable code:

Messenger.Register<CasualtyMessage, Party>(this, Party.Blanket, m => { OnCasualtyMessageReceived(); });
Messenger.Default.Send<CasualtyMessage, Party>(new CasualtyMessage(), Party.Pillow);

Dependency Injection

In an MVVM architecture your code base is divided into Views, ViewModels, and Models. Any other reusable code should be grouped into Services. There should be a way to locate and call these services from any component.

MVVMServices

ServiceLocator and DependencyInjection are two (related) common patterns to implement this. These patterns are independent from MVVM, but having a service container available in an MVVM app is useful/required in many cases, like

  • when you want to cache expensive ViewModels instead of recreating them every time a View is instantiated, or
  • when you want to access the messenging infrastructure from a non-ObservableRecipient (like a View).

WCT MVVM comes with an Ioc helper class around the IServiceProvider interface. It supports creating and using a service container, but does not come itself with another service provider. This allows you to stick to your favorite dependency injection framework: Autofac, Ninject, Castle Windsor, Microsoft.Extensions.DependencyInjection or any other. Our sample app uses that last one – very popular in ASP.NET Core:

DependencyInjectionNuGet

Here’s a screenshot of the test page, it demonstrates fetching services from the container, and constructor injection:

InversionOfControlPage

When the app starts up, it registers its services in the container (the Messenger instance, an expensive ViewModel, a service for Logging, and one for Dialogs) and builds the provider:

Ioc.Default.ConfigureServices
        (new ServiceCollection()
            .AddSingleton<IMessenger>(WeakReferenceMessenger.Default)
            .AddSingleton<ILoggingService, DebugLoggingService>()
            .AddSingleton<ColorModuleViewModel>()
            .AddSingleton<ModalView>()
            .BuildServiceProvider()
        );

At runtime, the app can now pull services out of the container with a call to one of the GetService() family members. Here’s how the expensive ViewModel is fetched by a View:

var viewModel = Ioc.Default.GetService<ColorModuleViewModel>();

And here’s a View getting a reference to the Messenger to send a message:

Ioc.Default.GetService<IMessenger>()
	.Send<CasualtyMessage, Party>(new CasualtyMessage(), Party.Pillow);

For the sake of completeness (and unrelated to MVVM) the sample app also demonstrates constructor injection. Here’s how a ViewModel fetches the Logging and the Dialog services when it’s instantiated:

public ColorModuleViewModel(ILoggingService loggingService, ModalView modalView)
{
    // ...
}

Wait, there’s more!

The new WCT MVVM library is familiar, fast, and flexible. But there’s more coming your way than just the NuGet package. In the near future you may also expect:

In mean time our sample UWP app lives here on Github.

Enjoy!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s