Introducing the brand-new MvvmGen Library – Writing ViewModels for your XAML Applications Has Never Been More Productive and Easier

In the nights of the past weeks, I built a brand-new MVVM library that you can use in your XAML-based .NET applications. The library is called MvvmGen. It uses Roslyn-powered C# Source Generators to create all the ViewModel-specific boilerplate for you, and it is built with .NET Standard 2.0, which means you can use it in your WPF, WinUI, Uno Platform, Xamarin.Forms and .NET MAUI apps.

MvvmGen is a modern, next-generation MVVM library that I built from ground up with a strong focus on C# Source Generators. All the repetitive code (also known as boilerplate) that you normally write to create a ViewModel class gets generated for you. So, let’s welcome the new library and let’s take a look at it.

Say Welcome to the brand-new MvvmGen Library

MvvmGen is a brand-new library that contains everything you need to build XAML applications with the popular Model-View-ViewModel-pattern (MVVM):

  • A ViewModelBase class
  • An ICommand implementation
  • An EventAggregator to communicate between ViewModels

But the key part of MvvmGen are its attributes that you use to hook up MvvmGen’s ViewModelGenerator. The ViewModelGenerator is a modern C# Source Generator that generates the boilerplate for your ViewModel classes behind the scenes while you type your code in Visual Studio.

I decided to provide MvvmGen for free under the MIT license. MvvmGen is available as a NuGet package, and it is open source.

Now, back to this blog post. Before I explain you the basics of MvvmGen, let me show you what a ViewModel created with MvvmGen looks like, so that you get a clear picture of the library.

What Does an MvvmGen ViewModel Look Like?

MvvmGen contains attributes like ViewModel, Property, Command and Inject. You set these attributes on a partial class and its members that you create. The ViewModel attribute marks your class as a ViewModel. Look at the beautiful code snippet below, this is a full-blown ViewModel created with MvvmGen.

using MvvmGen;
using MvvmGen.Events;

namespace MyWinUiApp
{
  [Inject(typeof(IEventAggregator))]
  [ViewModel]
  public partial class EmployeeViewModel
  {
    [Property] private string _firstName;
    [Property] private string _lastName;

    [Command(CanExecuteMethod = nameof(CanSave))]
    private void Save()
    {
      EventAggregator.Publish(new EmployeeSavedEvent(FirstName, LastName));
    }

    [CommandInvalidate(nameof(FirstName))]
    private bool CanSave()
    {
      return !string.IsNullOrEmpty(FirstName);
    }
  }
}

For the above class, MvvmGen’s ViewModelGenerator creates on-the-fly the following partial class definition based on the attributes that you have set on your class and its members.

// <auto-generated>
//   This code was generated for you by
//   ⚡ MvvmGen, a tool created by Thomas Claudius Huber (https://www.thomasclaudiushuber.com)
//   Generator version: 1.0.0
// </auto-generated>
using MvvmGen.Commands;
using MvvmGen.Events;
using MvvmGen.ViewModels;

namespace MyWinUiApp
{
  partial class EmployeeViewModel : ViewModelBase
  {
    public EmployeeViewModel(MvvmGen.Events.IEventAggregator eventAggregator)
    {
      this.EventAggregator = eventAggregator;
      this.InitializeCommands();
      this.OnInitialize();
    }

    partial void OnInitialize();

    private void InitializeCommands()
    {
      SaveCommand = new DelegateCommand(_ => Save(), _ => CanSave());
    }

    public DelegateCommand SaveCommand { get; private set; }

    public string FirstName
    {
      get => _firstName;
      set
      {
        if (_firstName != value)
        {
          _firstName = value;
          OnPropertyChanged("FirstName");
          SaveCommand.RaiseCanExecuteChanged();
        }
      }
    }

    public string LastName
    {
      get => _lastName;
      set
      {
        if (_lastName != value)
        {
          _lastName = value;
          OnPropertyChanged("LastName");
        }
      }
    }

    protected MvvmGen.Events.IEventAggregator EventAggregator { get; private set; }
  }
}

As you can see in the code snippet above, the generated class inherits from ViewModelBase, which is MvvmGen‘s base class for ViewModels. It implements the INotifyPropertyChanged interface. The generated class also has a constructor that has an IEventAggregator parameter, and that parameter value is stored in the generated, protected EventAggregator property. When you look at the first code snippet, you can see that this generated EventAggregator property is used in the Save method to publish an event. An event can be any type, typically you use C# records to define events. More to this later in this blog post. The generated class above has also a SaveCommand property that gets initialized with a DelegateCommand instance that points to the methods Save and CanSave. The generated class has also the properties FirstName and LastName and in the setters of these properties the OnPropertyChanged method of the ViewModelBase class is called to raise the PropertyChanged event. In the setter of the FirstName property also the SaveCommand‘s RaiseCanExecuteChanged method is called to raise the command’s CanExecuteChanged event. This happens because of the CommandInvalidate attribute in the first code snippet. We will go into the details later in this blog post. Here the point is that you should get a little impression of MvvmGen. You have to write the code that you see in the first code snippet above, and everything that you see in the second code snippet gets generated for you while you type, so it’s immediately available and ready to be used in your code. Also notice how focused the first code snippet is that contains the few lines of code that you have to write to create a full-blown ViewModel with MvvmGen, and how much code is generated for you in the partial class definition that you see in the second code snippet.

Now you have a little impression of what MvvmGen does for you. To get started, all you need to do is to reference the MvvmGen NuGet package in a project that supports .NET Standard 2.0, and then you add a few attributes to your classes, that’s it!!!

Note: You find sample applications built with WinUI, WPF, and MvvmGen in this GitHub repository. I’ll talk more about these sample applications at the end of this blog post.

Before we look at the different features of MvvmGen in more detail, let’s go a bit back in time, and let me show you how I used code generators like T4 templates in the past.

Thomas and Code Generation in the Past

In the past and also today you can choose between several great MVVM libraries to build a XAML app with the MVVM pattern, but with most of them you have to write repetitive code for properties, commands, and injected dependencies. As mentioned, that repetitive code is called boilerplate.

Note: The MVVM Toolkit and Prism are also getting new features that allow you to generate the boilerplate!

I started with WPF in 2006, and since then, I have built many huge MVVM applications for my customers, and I still do this today. While building a XAML app with MVVM, no matter if I used an MVVM library or not, the pain point for me was and still is the boilerplate that I have to write to create a ViewModel class. In the past years, I used code generators like T4 templates to generate for example ViewModel classes from Model classes, so that you get automatically the full properties that raise a PropertyChanged event in their setters. I have described these concepts and code generation with T4 templates in the Pluralsight course WPF and MVVM: Advanced Model Treatment. But T4 templates have the disadvantage that they run after the compilation of your code, and not during the compilation process. That means that if you add for example a property to a model class, then you have to compile the project with the model classes, and after that you have to run the T4 template to generate the ViewModels from the model classes, and then you can use the generated sources of the ViewModels in your code. This whole workflow means that you have to trigger the generator, and the generator gets your compiled sources as input. This process is not optimal, as it’s not integrated into the normal compilation, and as you don’t get the new Model properties immediately in your ViewModels, you always have to do the manual steps. But with the .NET 5.0 SDK, there is a new way: C# Source Generators.

C# Source Generators for the Win

With the introduction of Roslyn-powered C# Source Generators as part of the .NET 5.0 SDK, the game has changed. C# Source Generators can generate code on-the-fly while your type code in the code editor. The generated code is immediately available for you to use. How does this work? C# Source Generators allow you to hook up a code generator into the Roslyn compiler, and that generator can generate code as part of the compilation process. But the fantastic thing is that the generated code gets even available for you while you write your code in Visual Studio, as a compilation runs behind the scenes many many times when you’re editing your code files.

Important to understand is that a C# Source Generator works on a lower level than a T4 template. A T4 template gets your assemblies – the compiled sources – as input. But a C# Source Generator on the other side gets the syntax as input, as it is called as part of the compilation process. That means that the compiled sources are not created yet when the C# Source Generator is called. With a C# Source Generator, you can analyze the syntax and symbols of the existing code in the compilation process – this is quite similar to a Roslyn-based syntax analyzer. Then, based on the analysis, the C# Source Generator can add additional, generated code to the compilation.

A C# Source Generator can not change existing code, it can only add additional code.

All this code generation happens on-the-fly, no matter if you type in Visual Studio, or if you build your project with Visual Studio or for example with the .NET CLI.

When I saw C# Source Generators for the first time, I thought:

WOW!!!

C# Source Generators allow me to generate code in a brand-new way for XAML applications that use the MVVM pattern. Over the past months, I spent weekends and nights with C# Source Generators and MVVM. I noticed soon that to get the best out of C# Source Generators for XAML applications,

a brand new, modern, lightweight, and next-generation MVVM library is needed that is built from ground up with a strong focus on the powerful C# Source Generators.

Thomas Claudis Huber

And now, that MVVM library is here, and it is called MvvmGen. Now, let’s walk through the most important features of MvvmGen, and let’s start at the beginning: The installation of the MvvmGen NuGet package.

Note: You might ask yourself: Why a new library, and why not contributing to Prism or to the MVVM Toolkit? I decided to create a brand new library that let’s me focus purely on all the advantages of C# Source Generators, without having to think about all the existing stuff. MvvmGen is also a “Source Generator First” framework, it’s driven by features of C# Source Generators. Existing frameworks might use Source Generators more to augment what they do already, but we’ll see what happens there in the future. All this doesn’t mean that I won’t contribute to the other MVVM frameworks in the future, as I love the frameworks and the great people who are working on them. And the other frameworks are getting C# Source Generator features too. Michael Hawker pointed out on twitter that the next version of the MVVM Toolkit has also attributes that make use of C# Source Generators. Also Dan Siegel from Prism said on twitter that he’s working on C# Source Generators for the Prism.Magician. So, you’ll see, in the close future, applying the MVVM pattern will be even more fun, no matter which framework you use.

Install the MvvmGen NuGet Package

To use MvvmGen, you install the MvvmGen NuGet package in your WPF, WinUI, Uno Platform, Xamarin.Forms or .NET MAUI app, or in a .NET class library where you want to create your ViewModels. As MvvmGen is a .NET Standard 2.0 library, you can use it in different .NET projects that support .NET Standard 2.0. To install the MvvmGen NuGet package, you can use in Visual Studio the user interface, or you can use Powershell:

Install-Package MvvmGen

Or you can also use the .NET CLI:

dotnet add package MvvmGen

After installing the MvvmGen NuGet package, you’re ready to create your first ViewModel.

Note that you should have the latest version of Visual Studio installed, so that C# Source Generators will work for you. Also the latest .NET 5.0 SDK is recommended.

Create Your First ViewModel

As an example for this blog post, I created a new WPF app that targets .NET 5.0 and that references the MvvmGen NuGet package. To this blank app, I added a ViewModel folder with an EmployeeViewModel class that you see below. As you can see, it is a partial class and it has the ViewModel attribute from the MvvmGen namespace set:

using MvvmGen;

namespace MyWpfApp.ViewModel
{
  [ViewModel]
  public partial class EmployeeViewModel
  {
  }
}

That ViewModel attribute marks your class as a ViewModel. Behind the scences, it tells MvvmGen’s internal ViewModelGenerator to generate a partial EmployeeViewModel class. You can see that generated class when you look in the Solution Explorer under your project into Dependencies => Analyzers. Expand the MvvmGen.SourceGenerators node and you’ll see the files generated by the ViewModelGenerator. In this case you see there an EmployeeViewModel.g.cs file, prefixed with the full namespace.

When you open the EmployeeViewModel.g.cs file, you can see the generated code. Not so much right now. It looks like below. As you can see, the class inherits from ViewModelBase, which is the base class for ViewModels that you create with the MvvmGen library (Note: You can also inherit your class in the code snippet above from a custom ViewModelBase class, this is supported too. Then the generated file wouldn’t have ViewModelBase as a base class):

// <auto-generated>
//   This code was generated for you by
//   ⚡ MvvmGen, a tool created by Thomas Claudius Huber (https://www.thomasclaudiushuber.com)
//   Generator version: 1.0.0
// </auto-generated>
using MvvmGen.Commands;
using MvvmGen.Events;
using MvvmGen.ViewModels;

namespace MyWpfApp.ViewModel
{
    partial class EmployeeViewModel : ViewModelBase
    {
        public EmployeeViewModel()
        {
            this.OnInitialize();
        }

        partial void OnInitialize();
    }
}

Now let’s start to implement the ViewModel. Let’s add some properties.

Adding Properties to the ViewModel

To add properties to the ViewModel, you use the Property attribute on your fields like below:

using MvvmGen;

namespace MyWpfApp.ViewModel
{
  [ViewModel]
  public partial class EmployeeViewModel
  {
    [Property] private string _firstName;
    [Property] private bool _isDeveloper;
    [Property] private string _updateComment;
  }
}

Now, while you type the fields in Visual Studio, the generation happens behind the scences on-the-fly, as your syntax gets analyzed by MvvmGen’s ViewModelGenerator, and the generated class looks then like below.

You can actually keep the generated EmployeeViewModel.g.cs file open, and you’ll see the code generation in action while you’re typing.

As you can see in the code snippet below, the properties for the fields are generated and in their setters the OnPropertyChanged method of the ViewModelBase class is called to raise the PropertyChanged event.

partial class EmployeeViewModel : ViewModelBase
{
  public EmployeeViewModel()
  {
    this.OnInitialize();
  }

  partial void OnInitialize();

  public string FirstName
  {
    get => _firstName;
    set
    {
      if (_firstName != value)
      {
        _firstName = value;
        OnPropertyChanged("FirstName");
      }
    }
  }

  public bool IsDeveloper
  {
    get => _isDeveloper;
    set
    {
      if (_isDeveloper != value)
      {
        _isDeveloper = value;
        OnPropertyChanged("IsDeveloper");
      }
    }
  }

  public string UpdateComment
  {
    get => _updateComment;
    set
    {
      if (_updateComment != value)
      {
        _updateComment = value;
        OnPropertyChanged("UpdateComment");
      }
    }
  }
}

Calling Custom Methods From a Property Setter

Sometimes you might want to call a custom method from a setter. You can do this with MvvmGen’s PropertyCallMethod attribute in your ViewModel like this:

[PropertyCallMethod(nameof(CustomMethod), MethodArgs ="value")]
[Property]
private string? _updateComment;

private void CustomMethod(string comment) { }

The generated property looks now like this, note the call to the CustomMethod in the setter:

public string? UpdateComment
{
  get => _updateComment;
  set
  {
    if (_updateComment != value)
    {
      _updateComment = value;
      OnPropertyChanged("UpdateComment");
      CustomMethod(value);
    }
  }
}

Generating Properties from a Model

Sometimes you want to wrap a Model in a ViewModel. MvvmGen’s ViewModel attribute allows you to specify the wrapped model type. Let’s say you have a model class like this:

namespace MyWpfApp.Model
{
  public class Employee
  {
    public int Id { get; set; }
    public string? FirstName { get; set; }
    public bool IsDeveloper { get; set; }
  }
}

Then you could create the EmployeeViewModel also like below without explicitly specifying the fields _firstName and _isDeveloper with the Property attribute.

using MvvmGen;
using MyWpfApp.Model;

namespace MyWpfApp.ViewModel
{
  [ViewModel(ModelType = typeof(Employee))]
  public partial class EmployeeViewModel
  {
    [Property] private string _updateComment;
  }
}

Now, when you look at the generated code for the ViewModel above, it looks like below. Note how the properties Id, FirstName and IsDeveloper are generated, and they use in their getters and setters the Employee model that is accessed via the generated, protected Model property that you see at the bottom of the following code snippet:

partial class EmployeeViewModel : ViewModelBase
{
  public EmployeeViewModel()
  {
    this.OnInitialize();
  }

  partial void OnInitialize();

  public string UpdateComment
  {
    get => _updateComment;
    set
    {
      if (_updateComment != value)
      {
        _updateComment = value;
        OnPropertyChanged("UpdateComment");
      }
    }
  }

  public int Id
  {
    get => Model.Id;
    set
    {
      if (Model.Id != value)
      {
        Model.Id = value;
        OnPropertyChanged("Id");
      }
    }
  }

  public string? FirstName
  {
    get => Model.FirstName;
    set
    {
      if (Model.FirstName != value)
      {
        Model.FirstName = value;
        OnPropertyChanged("FirstName");
      }
    }
  }

  public bool IsDeveloper
  {
    get => Model.IsDeveloper;
    set
    {
      if (Model.IsDeveloper != value)
      {
        Model.IsDeveloper = value;
        OnPropertyChanged("IsDeveloper");
      }
    }
  }

  protected MyWpfApp.Model.Employee Model { get; set; }
}

Now, to initialize the Model property when the EmployeeViewModel is created, you can use in your code the partial OnInitialize method like you see it below. That method gets called from the generated constructor.

[ViewModel(ModelType = typeof(Employee))]
public partial class EmployeeViewModel
{
  [Property] private string _updateComment;

  partial void OnInitialize()
  {
    Model = new Employee
    {
      FirstName = "Thomas Claudius",
      IsDeveloper = true
    };
  }
}

Now, let’s look at Commands.

Working with Commands

To add a command to your ViewModel, you just decorate a method with the Command attribute like below. That’s it!

[Command]
private void Save() { }

In the generated partial class definition you’ll then find a SaveCommand property of type DelegateCommand, like you see it in the next code snippet. Note that from the constructor, the generated InitializedCommands method is called that initializes the SaveCommand property with a new DelegateCommand instance.

partial class EmployeeViewModel : ViewModelBase
{
  public EmployeeViewModel()
  {
    this.InitializeCommands();
    this.OnInitialize();
  }

  partial void OnInitialize();

  private void InitializeCommands()
  {
    SaveCommand = new DelegateCommand(_ => Save());
  }

  public DelegateCommand SaveCommand { get; private set; }
  ...
}

If you need a method for the can-execute logic too, you specify it like below with the Command attribute’s CanExecuteMethod property.

[Command(CanExecuteMethod = nameof(CanSave))]
private void Save() { }

private bool CanSave()
{
  return true;
}

Note: The generator could find the can-execute method with a naming convention. For example, in case of the Save method from the code snippet above, the ViewModelGenerator could look for a CanSave method, and automatically use that one as a can-execute method for the command. It would have been easy to implement this, but I decided against it, as the explicit way is easier to read and understand, it’s not too much magic, and setting the CanExecuteMethod property on the Command attribute is not much more for you to write.

Now, what if you implement the CanSave method like this:

private bool CanSave()
{
   return !string.IsNullOrEmpty(FirstName);
}

Now the result of the CanSave method depends on the value of the FirstName property. This means that you should raise the CanExecuteChanged event of the SaveCommand in the setter of the generated FirstName property, so that the CanSave method is called again when the FirstName property changes. To do this, you set the CommandInvalidate attribute either on the execute method or on the can-execute method of the command. I’m more a fan of setting it on the can-execute method like below on the CanSave method, but it would work the same way if you would set the CommandInvalidate attribute on the Save method:

[Command(CanExecuteMethod = nameof(CanSave))]
private void Save() { }

[CommandInvalidate(nameof(FirstName))]
private bool CanSave()
{
  return !string.IsNullOrEmpty(FirstName);
}

When you now look at the setter of the generated FirstName property in the code snippet below, you can see that it calls the RaiseCanExecuteChanged method of the SaveCommand.

public string FirstName
{
  get => Model.FirstName;
  set
  {
    if (Model.FirstName != value)
    {
      Model.FirstName = value;
      OnPropertyChanged("FirstName");
      SaveCommand.RaiseCanExecuteChanged();
    }
  }
}

Of course, you can set multiple CommandInvalidate attributes to invalidate a command in the setters of different generated properties.

Injecting Services into Your ViewModel

Usually you add constructor parameters to your ViewModel class, so that you can pass dependencies to it. This keeps your ViewModel loosely coupled and testable. Also for this very typical scenario, MvvmGen has a feature. Let’s say you have an EmployeeDataProvider implementation like below that you use to save an Employee. The Save method could save an Employee to a database, to a file or to any other place.

public interface IEmployeeDataProvider
{
  void Save(Employee employee);
}

public class EmployeeDataProvider : IEmployeeDataProvider
{
  public void Save(Employee employee)
  {
    // TODO: Save employee to a file, a db, a REST API etc. 
  }
}

The ViewModel would just depend on the IEmployeeDataProvider interface. So, in a unit test, you mock this interface with a test implementation that does not access the real database, and in your app, you use the real EmployeeDataProvider. Now, to inject a service like an IEmployeeDataProvider instance into your ViewModel, you use MvvmGen’s Inject attribute on your ViewModel class. With the Inject attribute, you define the service type that you want to inject, in this case an IEmployeeDataProvider:

[Inject(typeof(IEmployeeDataProvider))]
[ViewModel(ModelType = typeof(Employee))]
public partial class EmployeeViewModel
{ ... }

Now the generated class has an IEmployeeDataProvider constructor parameter, as you can see it in the next code snippet. That constructor parameter initializes a protected EmployeeDataProvider property that you can use in your code.

partial class EmployeeViewModel : ViewModelBase
{
  public EmployeeViewModel(MyWpfApp.Data.IEmployeeDataProvider employeeDataProvider)
  {
    this.EmployeeDataProvider = employeeDataProvider;
    ...
  }
  ...

  protected MyWpfApp.Data.IEmployeeDataProvider EmployeeDataProvider { get; private set; }
}

Now, again, it’s important to understand that as soon as you have set the [Inject(typeof(IEmployeeDataProvider))] attribute on your ViewModel class, the EmployeeDataProvider property is immediately available for you to use, as the code generation happens on-the-fly while you type your code. That means, in your ViewModel, you can immediately use the EmployeeDataProvider property for example in the Save method like you see it in the following code snippet:

[Inject(typeof(IEmployeeDataProvider))]
[ViewModel(typeof(Employee))]
public partial class EmployeeViewModel
{
  [Property] private string _updateComment;

  partial void OnInitialize()
  {
    Model = new Employee
    {
      FirstName = "Thomas Claudius",
      IsDeveloper = true
    };
  }

  [Command(CanExecuteMethod = nameof(CanSave))]
  private void Save()
  {
    EmployeeDataProvider.Save(Model);
  }

  [CommandInvalidate(nameof(FirstName))]
  private bool CanSave()
  {
    return !string.IsNullOrEmpty(FirstName);
  }
}

Working with the Event Aggregator

To communicate between ViewModels, you can use MvvmGen’s event aggregator implementation. Let’s look at this. An event in MvvmGen can be anything. This was important to me, as I love C# records. Typically, with C# 9.0 or later, you define an event with a simple record like this:

public record EmployeeSavedEvent(int id, string? FirstName);

To publish such an event, you inject an MvvmGen.Events.IEventAggregator into your ViewModel with the Inject attribute, and then you use the generated EventAggregator property like you see it in the Save method of the ViewModel below:

[Inject(typeof(IEventAggregator))]
[Inject(typeof(IEmployeeDataProvider))]
[ViewModel(typeof(Employee))]
public partial class EmployeeViewModel
{
  [Property] private string _updateComment;

  partial void OnInitialize()
  {
    Model = new Employee
    {
      FirstName = "Thomas Claudius",
      IsDeveloper = true
    };
  }

  [Command(CanExecuteMethod = nameof(CanSave))]
  private void Save()
  {
    EmployeeDataProvider.Save(Model);
    EventAggregator.Publish(new EmployeeSavedEvent(Model.Id, Model.FirstName));
  }

  [CommandInvalidate(nameof(FirstName))]
  private bool CanSave()
  {
    return !string.IsNullOrEmpty(FirstName);
  }
}

To subscribe from another ViewModel to this event, you implement the generic IEventSubscriber interface that defines an OnEvent method. You see an implementation of this interface below:

[ViewModel]
public partial class NavigationViewModel : IEventSubscriber<EmployeeSavedEvent>
{
  public void OnEvent(EmployeeSavedEvent eventData) { }
}

When you look at the generated code of this NavigationViewModel class, you’ll see that an IEventAggregator constructor parameter is created, and in the constructor the RegisterSubscriber method is called on the IEventAggregator to register the ViewModel instance as an event subscriber:

partial class NavigationViewModel : ViewModelBase
{
  public AnotherViewModel(MvvmGen.Events.IEventAggregator eventAggregator)
  {
    eventAggregator.RegisterSubscriber(this);
    this.OnInitialize();
  }

  partial void OnInitialize();
}

This means for you, that you just implement the IEventSubscriber interface, and your OnEvent method is called when the event was published. There’s nothing more for you to do. If you need to subscribe to multiple events, you can implement the IEventSubscriber interface multiple times, or you use overloads of this interface that have multiple generic type parameters. If you need to publish events in addition, you use the Inject attribute to inject the IEventAggregator, so that you can call EventAggregator.Publish in your code.

Publish an Event from a Property Setter

Sometimes you might want to publish an event when a property changes. You could use the PropertyCallMethod attribute to do this. But there is a better way: The PropertyPublishEvent attribute. The following field has that attribute set. Beside the mandatory event type, you can specify optional EventConstructorArgs and an optional PublishCondition:

[PropertyPublishEvent(typeof(EmployeeNavigationSelectedEvent),
  EventConstructorArgs = "value.Id",
  PublishCondition = "value is not null")]
[Property]
private NavigationItemViewModel? _selectedItem;

The generated property for the field above looks like this:

public EmployeeManager.ViewModel.NavigationItemViewModel? SelectedItem
{
  get => _selectedItem;
  set
  {
    if (_selectedItem != value)
    {
      _selectedItem = value;
      OnPropertyChanged("SelectedItem");
      if (value is not null)
      {
        EventAggregator.Publish(new EmployeeManager.ViewModel.Events.EmployeeNavigationSelectedEvent(value.Id));
      }
    }
  }
}

Of course, if you do that, you should also inject an IEventAggregator into your ViewModel.

Generating ViewModel Factories

Sometimes you need to create a random number of ViewModel instances inside of another ViewModel. A typical case is when you have for example a MainViewModel that has an ObservableCollection of EmployeeViewModel objects. When a user selects an employee in the navigation, the MainViewModel creates a new EmployeeViewModel instance, adds it to its own collection, and that collection could be bound in the view for example by a TabControl, so the selected employee shows up in a new tab page.

But now, with dependency injection in place, the creation of an EmployeeViewModel shouldn’t be done with a hard-coded constructor call in the MainViewModel. If you do that, you always have to adjust that constructor call when you change the constructor parameters of the EmployeeViewModel. To solve this, you should use a factory in the MainViewModel that allows you to create an EmployeeViewModel without manually calling its constructor.

Some dependency injection frameworks support these factories with a Func<T>. That means, you can inject a Func<EmployeeViewModel> into the MainViewModel, and when you call that function, you get a new EmployeeViewModel instance, and the dependency injection framework calls the constructor for you and it passes all the necessary constructor parameters to the EmployeeViewModel constructor. Now, the problem is that not all dependency injection frameworks support factories via the Func<T> delegate. And for these frameworks, you should implement a factory that can create a ViewModel for you. MvvmGen has an interface for such a factory. As you can see in the following code snippet, the generic IViewModelFactory<T> interface has a parameterless Create method to create a ViewModel of type T.

public interface IViewModelFactory<out T> where T : ViewModelBase
{
  T Create();
}

Of course, MvvmGen wouldn’t be MvvmGen if you would have to implement the IViewModelFactory<T> interface on your own. With MvvmGen you use the ViewModelGenerateFactory attribute to generate an implementation of IViewModelFactory<T>. You set that attribute on a ViewModel like you see it in the following code snippet:

[Inject(typeof(IEmployeeDataProvider))]
[Inject(typeof(IEventAggregator))]
[ViewModelGenerateFactory]
[ViewModel(typeof(Employee))]
public partial class EmployeeViewModel
{
    ...
}

The attribute adds at the bottom of the generated EmployeeViewModel.g.cs file the following code. As you can see, an IEmployeeViewModelFactory interface is created, and that interface inherits from IViewModelFactory<EmployeeViewModel>. Then there is an EmployeeViewModelFactory class that implements the IEmployeeViewModelFactory interface, and its Create method returns a new EmployeeViewModel instance by calling the constructor. The necessary constructor parameters, in this case the IEventAggregator and the IEmployeeDataProvider are passed to the EmployeeViewModel constructor by the factory.


public interface IEmployeeViewModelFactory : IViewModelFactory<EmployeeViewModel> { }

public class EmployeeViewModelFactory : IEmployeeViewModelFactory
{
  public EmployeeViewModelFactory(MvvmGen.Events.IEventAggregator eventAggregator, Sample.WpfApp.DataProvider.IEmployeeDataProvider employeeDataProvider)
  {
    this.EventAggregator = eventAggregator;
    this.EmployeeDataProvider = employeeDataProvider;
  }

  protected MvvmGen.Events.IEventAggregator EventAggregator { get; private set; }

  protected Sample.WpfApp.DataProvider.IEmployeeDataProvider EmployeeDataProvider { get; private set; }

  public EmployeeViewModel Create() => new EmployeeViewModel(EventAggregator, EmployeeDataProvider);
}

This means now that you can inject that factory into another ViewModel to create instances of the EmployeeViewModel. Look at the following snippet. The IEmployeeViewModelFactory is injected, and in the MainViewModel its Create method is called to create an EmployeeViewModel instance.

[Inject(typeof(IEmployeeViewModelFactory))]
[Inject(typeof(NavigationViewModel), PropertyAccessModifier = AccessModifier.Public)]
[Inject(typeof(IEventAggregator))]
[ViewModel]
public partial class MainViewModel : IEventSubscriber<EmployeeNavigationSelectedEvent>
{
  public void OnEvent(EmployeeNavigationSelectedEvent eventData)
  {
    var employeeViewModel = EmployeeViewModels
      .SingleOrDefault(x => x.Id == eventData.EmployeeId);
    if (employeeViewModel is null)
    {
      employeeViewModel = EmployeeViewModelFactory.Create();
      employeeViewModel.Load(eventData.EmployeeId);
      EmployeeViewModels.Add(employeeViewModel);
    }

    SelectedEmployee = employeeViewModel;
  }
  ...
}

Now, with the factory in place, it means that you can inject for example another service into the EmployeeViewModel by using MvvmGen’s Inject attribute, that one generates a new constructor parameter in the EmployeeViewModel, and it also updates the generated EmployeeViewModelFactory to create the EmployeeViewModel with that new constructor parameter, and so, in the end, everything just works with your factory when you inject other services, as everything gets generated on-the-fly in the compilation process.

While working with MvvmGen, I must say that I’m a fan of the generated factories. Even if the dependency injection framework supports Func<EmployeeViewModel> as a factory, I prefer the nice and clean interface IEmployeeViewModelFactory. I think the interface is even easier to understand for beginners.

Give Me a Sample

Yes, sure. I’ve created applications with WinUI and also with WPF that target .NET 5 and that show you how to use MvvmGen to build a tabbed user interface with the MVVM pattern. The WinUI application looks like this:

The WPF sample is similar:

Both projects are in the same solution, and the ViewModels are shared between the WinUI app and the WPF app with a .NET Standard 2.0 library. That library references the MvvmGen NuGet package to generate the ViewModels. Here you see the solution and the generated ViewModels in the EmployeeManager.ViewModel project:

As you can see in the screenshot above, the solution has different ViewModels. The solution uses dependency injection from Microsoft, it uses MvvmGen’s EventAggregator and ViewModel factories and much more. The applications store the employee data in a file, so that it’s simple for you to run the apps. You’ll find in that solution all the details that I explained in this blog post. Go and grab it from GitHub, and leave any questions and suggestions here below this blog post:

https://github.com/thomasclaudiushuber/mvvmgen-samples

Summary

MvvmGen is a brand-new library, and as you learned in this blog post, it allows you to build ViewModels in a highly productive way without writing all that boilerplate. Please try the MvvmGen NuGet Package and let me know what you think about it.

It’s a 1.0.0 release, but I’m committed to the API if you plan to use it. I don’t plan changes in the existing APIs for new releases.

What’s Next?

As mentioned, I’ll open source MvvmGen this month, May 2021. I focus right now primarily on bug fixes. Also Nullable reference types is something I have to look at for the generated code. Right now, you might get a few warnings as the nullable context is not turned on. I’ll fix these, and after that I have plans for more features. I’ll look into async methods for commands. Right now, defining an async command method will just work, and the generator will pass an async lambda to the DelegateCommand constructor. But for long-running commands and for exception handling in asynchronous scenarios, this is not optimal, and it will be improved with an upcoming release. Another feature is input validation. Ha, even friends at Microsoft might know that input validation is my favorite. It’s still a missing piece in WinUI. Once things get more clear there, I plan to provide something as part of MvvmGen. In my opinion, validating user input should be as easy as possible for you as a programmer.

Once the MvvmGen library is open source, we can also have discussions on GitHub about upcoming features. For now, just comment this blog post or write me an email via the contact form on this web site.

Happy coding,
Thomas

Share this post

Comments (11)

  • Laurent Kempé Reply

    Fantastic job Thomas! I look forward to trying MvvmGen as it looks very promising and also into its source code.

    May 13, 2021 at 9:52 am
    • Thomas Claudius Huber Reply

      Thank you Laurent, happy to read that you like what you see. Yes, I will release the source code in May.

      May 13, 2021 at 10:00 am
      • Laurent Kempé Reply

        I read it in the post Looking forward to having a look to it! In the meantime, I am playing a bit with it.

        May 13, 2021 at 1:53 pm
  • Mike Ward Reply

    I’m excited to use this. I’ve been using a library called Jab for dependency injection that uses source code generators and really like it.

    Question: Are there any runtime dependencies (ViewModelBase for instance) or does that code get generated and inserted into the project?

    May 13, 2021 at 1:47 pm
    • Thomas Claudius Huber Reply

      Hi Mike, yes, there’s a runtime dependency on the MvvmGen.dll that is part of the NuGet package, the generator itself sits in an MvvmGen.SourceGenerators.dll file. The MvvmGen.dll contains ViewModelBase, EventAggregator, DelegateCommand and the attributes that you use on a ViewModel.

      But you’re totally right, theoretically, it would be possible to generate these parts too, which means that you wouldn’t have an additional .dll to reference.

      May 13, 2021 at 3:35 pm
      • Thomas Claudius Huber Reply

        Would you prefer generated files only?

        May 13, 2021 at 4:03 pm
        • Mike Ward Reply

          Yes

          May 13, 2021 at 5:44 pm
          • Thomas Claudius Huber

            Cool, thank you Mike. What would you think about two packages:
            MvvmGen – comes with source generator and library as a runtime dependency (exactly what we have now)
            MvvmGen.Pure – comes only with a source generator, and library code gets generated too when the generator gets initialized, no runtime dependency.
            (I’m not sure of the name about the second one).

            Both would allow you to do exactly the same things, actually the second one is the first, with the only difference that you also compile the library on your side.

            May 14, 2021 at 11:54 am
          • Mike Ward

            Sounds like it would be extra work for you. I would keep it the way it is and open Git issue on it when you open source the code. That way others can chime in. I may be an outlier and frankly, I would use the package regardless of the runtime dependency.

            May 14, 2021 at 1:23 pm
          • Thomas Claudius Huber

            Hi Mike, yes, it’s a bit of extra work, but I tried it already yesterday night. I found a good way with a build configuration that can push out both ways, with lib as runtime dependency, or lib generated.
            Thanks to your comment I noticed that I made the dependencies wrong. I had the runtime library with the attributes that pulls in the generator. But actually, it should be the other way, the generator should depend on the library. I changed this yesterday night. Now the library dependency can be removed and the generator can generate the library.

            I found a way to do this with MSBuild conditions, so you don’t have to open an issue then. :-) I’ll share more of this by the end of next week on my blog post. And I also try to open source the stuff within the next 10 days.

            Have a great weekend,
            Thomas

            May 14, 2021 at 4:34 pm
          • Thomas Claudius Huber May 21, 2021 at 9:03 am

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.