MvvmGen.PureCodeGeneration 1.3.0

dotnet add package MvvmGen.PureCodeGeneration --version 1.3.0                
NuGet\Install-Package MvvmGen.PureCodeGeneration -Version 1.3.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MvvmGen.PureCodeGeneration" Version="1.3.0">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add MvvmGen.PureCodeGeneration --version 1.3.0                
#r "nuget: MvvmGen.PureCodeGeneration, 1.3.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install MvvmGen.PureCodeGeneration as a Cake Addin
#addin nuget:?package=MvvmGen.PureCodeGeneration&version=1.3.0

// Install MvvmGen.PureCodeGeneration as a Cake Tool
#tool nuget:?package=MvvmGen.PureCodeGeneration&version=1.3.0                

⚡ MvvmGen - a Lightweight and Modern MVVM library

MvvmGen is a lightweight and modern library that helps you to apply the popular Model-View-ViewModel-pattern (MVVM) in your XAML applications. MvvmGen works for your apps that you build with WPF, WinUI, Xamarin.Forms, .NET MAUI, Uno Platform, AvaloniaUI, or any other .NET stack.

MvvmGen was created from ground up with a focus on C# Source Generators. With MvvmGen, a lot of your ViewModel code gets generated behind the scenes while you're typing code in your code editor. This makes MvvmGen the most productive MVVM library.

What's in the Package?

MvvmGen consists of three parts:

  • Framework classes needed to apply the MVVM pattern
    • A ViewModelBase class that implements INotifyPropertyChanged
    • A DelegateCommand class that implements ICommand
    • An EventAggregator class for ViewModel communication
  • Attributes to decorate your ViewModels
    • The [ViewModel] attribute is the most popular attribute, as it marks a class as a ViewModel. With this attribute set on a class, the source generator knows there's something to generate
    • There are several other attributes, like [Property], [Command], or [Inject], that tell the source generator what it should generate
  • A modern C# source generator
    • This is your best friend who generates the ViewModel boilerplate for you behind the scenes

Getting Started

To get started with MvvmGen, install either the NuGet package MvvmGen or MvvmGen.PureCodeGeneration.

dotnet add package MvvmGen
dotnet add package MvvmGen.PureCodeGeneration

From a usage perspective, both packages work exactly the same. The difference is in the code generation.

  • MvvmGen package - ViewModels are generated, but attributes and framework classes come from a referenced MvvmGen.dll that is part of the MvvmGen NuGet package.
  • MvvmGen.PureCodeGeneration package - Not only ViewModels are generated, but also attributes and framework classes. This means that your compiled assembly does not have a dependency on an MvvmGen.dll, as all the MvvmGen-specific code is generated at compile time.

If you need help for a decision: The MvvmGen package is the more popular package. But as the API of both packages is exactly the same, you can swap one for the other at any time.

Creating a ViewModel

To create a ViewModel with MvvmGen, you create a partial class that you decorate with the ViewModel attribute:

using MvvmGen;

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

Because of the ViewModel attribute, MvvmGen's source generator will generate another partial class behind the scenes like the one below:

using MvvmGen.Commands;
using MvvmGen.Events;
using MvvmGen.ViewModels;

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

        partial void OnInitialize();
    }
}

Next, let's generate some properties.

Generate Properties

To generate properties, you decorate your private fields with MvvmGen's Property attribute:

using MvvmGen;

namespace MyWpfApp.ViewModel
{
    [ViewModel]
    public partial class EmployeeViewModel
    {
        [Property] string _firstName;
        [Property] string _lastName;
    }
}

Below you can see the generated code. It contains the two properties FirstName and LastName. In the setters of these properties the PropertyChanged event is raised by calling the OnPropertyChanged method that is defined in the ViewModelBase class. This event notifies data bindings in the user interface about property changes.

using MvvmGen.Commands;
using MvvmGen.Events;
using MvvmGen.ViewModels;

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

        partial void OnInitialize();

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

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

So, as you can see in the code snippet above, all the property boilerplate is generated for you. Now, let's also generate a command.

Generate Commands

To generate a command, you decorate a method with the Command attribute like you see it in the code snippet below. If you have some can-execute logic, you set the attribute's optional CanExecuteMethod property. In the code snippet below it's set to the CanSave method. On this CanSave method there's a CommandInvalidate attribute that ensures in this case that the command's CanExecuteChanged event is raised everytime the ViewModel's FirstName property was changed.

using MvvmGen;

namespace MyWpfApp.ViewModel
{
    [ViewModel]
    public partial class EmployeeViewModel
    {
        [Property] string _firstName;
        [Property] string _lastName;

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

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

Below you see the generated code that contains now a SaveCommand property that gets initialized with an instance of MvvmGen's DelegateCommand class. The DelegateCommand instance points to the methods Save and CanSave defined in your code. There's also an InvalidateCommands method that raises the command's CanExecuteChanged event if the FirstName property was changed.

using MvvmGen.Commands;
using MvvmGen.Events;
using MvvmGen.ViewModels;

namespace MyWpfApp.ViewModel
{
    partial class EmployeeViewModel : global::MvvmGen.ViewModels.ViewModelBase
    {
        private IDelegateCommand? _saveCommand;

        public EmployeeViewModel()
        {
            this.OnInitialize();
        }

        partial void OnInitialize();

        public IDelegateCommand SaveCommand => _saveCommand ??= new DelegateCommand(_ => Save(), _ => CanSave());

        public string FirstName { ... }

        public string LastName { ... }

        protected override void InvalidateCommands(string? propertyName)
        {
            base.InvalidateCommands(propertyName);
            if (propertyName == "FirstName")
            {
                SaveCommand.RaiseCanExecuteChanged();
            }
        }
    }
}

Next, let's also inject and use a service.

Inject Services

With MvvmGen's Inject attribute you can inject one or more services into your ViewModel. In the code snippet below an IEventAggregator is injected. In the Save method the injected service is used to publish an event.

using MvvmGen;
using MvvmGen.Events;

namespace MyWpfApp.ViewModel
{
    public record EmployeeSavedEvent(string FirstName, string LastName);

    [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);
        }
    }
}

Below you can see the generated code. As you can see, there's a new constructor parameter of type IEventAggregator. The parameter is stored in an EventAggregator property that you can use in your code like demonstrated in the Save method in the code snippet above.

using MvvmGen.Commands;
using MvvmGen.Events;
using MvvmGen.ViewModels;

namespace MyWpfApp.ViewModel
{
    partial class EmployeeViewModel : global::MvvmGen.ViewModels.ViewModelBase
    {
        private IDelegateCommand? _saveCommand;

        public EmployeeViewModel(MvvmGen.Events.IEventAggregator eventAggregator)
        {
            this.EventAggregator = eventAggregator;
            this.OnInitialize();
        }

        ...

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

Learning More

Now you learned how to use some basic features of the MvvmGen library to build and generate ViewModels. If you want to learn more about MvvmGen:

  • Take a look at the official docs, which are in the docs folder of the MvvmGen repository
  • Browse the MvvmGen Samples repository. It contains for example the very popular EmployeeManager application built with WPF and WinUI that has a tabbed user interface.

Questions and Feedback

If you have any questions or feedback, you can always open an issue in the MvvmGen repository or you can also contact me, the author and maintainer of MvvmGen, via

Happy coding,
Thomas Claudius Huber (https://www.thomasclaudiushuber.com)

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.3.0 357 12/12/2023
1.2.1 1,258 3/30/2023
1.2.0 212 3/29/2023
1.1.5 855 3/26/2022
1.1.4 428 3/16/2022
1.1.3 844 2/11/2022
1.1.2 410 11/2/2021
1.1.1 415 5/21/2021
1.1.0 338 5/19/2021

Version 1.3.0:
- New CommandType property on [ViewModel] attribute to specify a custom IDelegateCommand implementation.
- New ModelPropertyName property on [ViewModel] attribute to set the name of the property that contains the wrapped model specified via the ModelType property.
- New ModelPropertiesToIgnore property on [ViewModel] attribute to set a comma-separated list of model properties that should not be generated for the model specified via the ModelType property.
- Fix nullable warnings when generating command properties.
- Fix interface generation when ViewModel has generic methods.
- Fix constructor generation when base ViewModel has [Inject] attributes.

Version 1.2.1:
- Ensure that [ViewModelGenerateInterface] also generates command properties

Version 1.2.0:
- New [ViewModelGenerateInterface] attribute to generate an interface for a ViewModel. This supports more unit testing scenarios
- If [ViewModelGenerateInterface] is set, [ViewModelGenerateFactory] will return the interface type instead of the ViewModel type.
- New ReturnType property on [ViewModelGenerateFactory] attribute allows you to explicitly define a return type of the factory.
- Source generator implements now the newer IIncrementalGenerator interface
- The model used by the source generator implements Equals to support caching between generation steps. This makes the generator more performant, which is especially noticable in larger solutions.
- Bug fix for [ViewModelGenerateFactory] attribute. When injecting an IEventAggregator into the ViewModel, the factory now also has the correct constructor parameters.
- Minor code optimizations