# MVVM Source Generators: Advanced Scenarios

## Introduction

Welcome to the second article of my mini-series about [MVVM Source Generators](https://learn.microsoft.com/dotnet/communitytoolkit/mvvm/generators/overview) for C# .NET. In the [previous post](https://ewerspej.hashnode.dev/introduction-to-mvvm-source-generators-for-dotnet), I discussed the basics and most important features that the [MVVM Community Toolkit](https://learn.microsoft.com/windows/communitytoolkit/mvvm/introduction) provides, specifically attributes that can be used to automatically generate properties and commands.

In this second part, I will show you how to intercept property setters in order to provide custom behavior, which you might be used to from developing *ViewModels* entirely by hand without using Source Generators. By intercepting the setters, we can define custom functionality that can be executed right before and right after changing the backing field of a property.

Last but not least, I will also demonstrate the beauty of auto-generated *RelayCommands*. In the past, developers added a lot of busy flags (properties) to their ViewModels in order to show some kind of busyness indicator (such as an *ActivityIndicator*, also known as a *spinner*) that informs the user that a longer operation is currently taking place.

Like in the previous post, I am using a *.NET MAUI* project (check out the [sample repository](https://github.com/ewerspej/maui-samples)) to demonstrate the functionality, but since the MVVM Community Toolkit is independent from UI frameworks, the same things apply to technologies like *Windows Presentation Foundation* (WPF) and *Xamarin.Forms*.

## Updated scenario

In order to demonstrate customized property setters as well as the awesome new way to indicate activity (or *busyness*) without flags, I have added a *Stepper* control to the UI from the [previous post](https://ewerspej.hashnode.dev/introduction-to-mvvm-source-generators-for-dotnet) to simulate the selection of how many copies of the address label should be printed. When the number of copies is set to `0` the popup won't open. I have also added an *ActivityIndicator* to be displayed while the popup is being opened:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672908305292/f3468664-23b7-44db-9cc9-3c6b68d0182d.png align="center")

The `AddressViewModel` receives two new properties which are called `Copies` and `IsBusy` and the `PrintAddress()` method will be changed to return an `async Task` in order to simulate a longer running operation:

```csharp
private int _copies;
public int Copies
{
    get => _copies;
    set => SetField(ref _copies, value);
}

private bool _isBusy;
public bool IsBusy
{
    get => _isBusy;
    set => SetField(ref _isBusy, value);
}

private async Task PrintAddressAsync()
{
    IsBusy = true;

    await Task.Delay(TimeSpan.FromSeconds(2));

    OnPrintAddress?.Invoke(FullAddress);

    IsBusy = false;
}
```

The *ActivityIndicator* is bound to the `IsBusy` flag in the XAML:

```xml
<ActivityIndicator
  IsVisible="{Binding IsBusy}"
  IsRunning="{Binding IsBusy}"/>
```

In the next steps, we will add some custom functionality to the setter of the `Copies` property before addressing the busy flags. We'll first look at how this is usually done without Source Generators followed by how you can take advantage of the MVVM goodness that the Source Generators provide without having to live without customized property setters.

## Custom Property Setters

Using the previously introduced Source Generator attributes may have left some readers who have working MVVM experience with some open questions. For example, there are situations where you would not only add an *observable* property that raises the `PropertyChanging` or `PropertyChanged` events, but you might actually need to *customize* the property setter to execute additional functionality *if and when* the property is either *about* to change or has *just* changed.

> **Opinion:** In my humble opinion, it's a bad practice to add a lot of functionality to a property setter. By adding a lot of complex statements or even loops to a setter, you're effectively mixing concerns, which makes them difficult to maintain. In the end, a setter is a like a method that updates a value and should have no unexpected side-effects. Adding a lot of extra functionality that belongs into a separate method can lead to the violation of the [Single Responsibility Principle](https://en.wikipedia.org/wiki/Single-responsibility_principle) (SRP) and should be avoided.

### Executing logic in classic setters

Let's say we want to execute some additional logic in the setter of our `Copies` property, e.g. to log the current and new values to the console, and also notify subscribers about the changing state. Usually, without Source Generators we would write something like this:

```csharp
private int _copies;
public int Copies
{
    get => _copies;
    set
    {
        if (value == _copies)
        {
            return;
        }

        //do something before property is changing
        Console.WriteLine($"Property {nameof(Copies)} is about to change. Current value: {Copies}, new value: {value}");
        OnPropertyChanging();        

        _copies = value;

        //do something after property changed
        Console.WriteLine($"Property {nameof(Copies)} is has changed. Current value: {Copies}, new value: {value}");
        OnPropertyChanged();
    }
}
```

> **Note:** For simplicity's sake I went with logging something to the console here instead of some advanced logic. Of course, it's also possible to execute some complex logic inside a property setter, although I recommend separating concerns whenever possible.

Now, how can we achieve something similar using the Source Generators, though?

### Executing logic in auto-generated setters

As it turns out, it's actually quite easy to add custom behavior to auto-generated property setters, because the MVVM Source Generators graciously provide partial methods *(signature only)* for us which we can "hook" into, meaning we can provide an implementation body for these methods.

Let's add the `Copies` property in the *MVVM Source Generator* way and then look at what is actually being generated for us. This is the property with the `[ObservableProperty]` attribute:

```csharp
[ObservableProperty]
private int _copies;
```

If you remember from the previous post, in the [Under the hood](https://ewerspej.hashnode.dev/introduction-to-mvvm-source-generators-for-dotnet#heading-under-the-hood) section, there are two methods, specifically, which are generated for us based on the property's name when using the `ObservableObject` base class together with the `[ObservableProperty]` attribute:

* `partial void On[PropertyName]Changing(<type> value)`
    
* `partial void On[PropertyName]Changed(<type> value)`
    

For the `Copies` property these auto-generated methods look like this:

```csharp
/// <summary>Executes the logic for when <see cref="Copies"/> is changing.</summary>
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
partial void OnCopiesChanging(int value);

/// <summary>Executes the logic for when <see cref="Copies"/> just changed.</summary>
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
partial void OnCopiesChanged(int value);
```

As we can see, these methods are actually `partial` methods that don't define a body. We will take advantage of that a bit further down, but first let's have a look at *when and where* those methods are invoked. This is the auto-generated property:

```csharp
/// <inheritdoc cref="_copies"/>
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public int Copies
{
    get => _copies;
    set
    {
        if (!global::System.Collections.Generic.EqualityComparer<int>.Default.Equals(_copies, value))
        {
            OnCopiesChanging(value);
            OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Copies);
            _copies = value;
            OnCopiesChanged(value);
            OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Copies);
        }
    }
}
```

Right in beginning of the setter, the equality of the `_copies` backing field and the new `value` is checked. Only if this comparison evaluates to `false`, meaning that the values are different, the setter logic is executed.

First, the `OnCopiesChanging()` method is invoked with the new `value` as an argument. Since the method doesn't actually have a body, nothing happens *\- yet*. That call is followed by raising the `PropertyChanging` event of the `INotifyPropertyChanging` interface.

Second, the value of the `_copies` backing field gets updated *before* `OnCopiesChanged()` is invoked using the new `value` as an argument. This is followed by raising the `PropertyChanged` event of the `INotifyPropertyChanged` interface.

This means that we can "hook" into the setter by providing implementation bodies for the `OnCopiesChanging()` and `OnCopiesChanged()` methods in order to achieve the same functionality as we did without the Source Generators:

```csharp
[ObservableProperty]
private int _copies;

partial void OnCopiesChanging(int value)
{
    Console.WriteLine($"Property {nameof(Copies)} is about to change. Current value: {Copies}, new value: {value}");
}

partial void OnCopiesChanged(int value)
{
    Console.WriteLine($"Property {nameof(Copies)} is has changed. Current value: {Copies}, new value: {value}");
}
```

**That's it*.*** That's *all* we have to do in order to add custom functionality for our property setters. If we wanted to, we could even access other properties or run some fancy logic. Yeah! 🎉

## Mixing approaches

For common and simple scenarios, the MVVM Source Generators are the easiest way to minimize your coding efforts and increase productivity by reducing this repetitive task to a minimum, but what about non-standard properties that require some special logic which cannot be achieved using the MVVM Source Generators?

In the rare case that you really cannot achieve some highly specialized behavior using the auto-generated properties, such as executing logic inside of getters, or inside setters independent of the result of the equality comparison, you can still implement your properties like you would have without using Source Generators. It is completely valid to mix the two approaches and use the best of both worlds.

Nothing stops you from implementing one property using a Source Generator attribute and another one by implementing it completely manually:

```csharp
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(IsOfLegalAge))]
private int _age;

public bool IsOfLegalAge => Nationality == Nation.USA ? Age >= 21 : Age >= 18;

private Nation _nationality;
public Nation Nationality
{
    get => _nationality;
    set
    {
        if(!SetField(ref _nationality)) return;
        OnPropertyChanged(nameof(IsOfLegalAge));
    }
}
```

## Goodbye, busy flags

In the beginning of this article, I have introduced an `IsBusy` property that is used to show or hide an *ActivityIndicator* and it is set manually at the beginning and at the end of the `PrintAddressAsync()` method:

```csharp
private async Task PrintAddressAsync()
{
    IsBusy = true;

    await Task.Delay(TimeSpan.FromSeconds(2));

    OnPrintAddress?.Invoke(FullAddress);

    IsBusy = false;
}
```

This is a common scenario in many ViewModels, but often you need to have various flags to indicate busyness for different operations and sometimes you just cannot reuse the same flag for that.

### Problems of busy flags

Doing this is problematic, because it scatters the code with flags and you may even run into issues when you have some complex logic that is running in the method that your command invokes.

I have often encountered bugs where busy flags have not been reset correctly, because a developer decided to *(rightfully!)* jump out of a method early if a certain condition isn't met and the developer *(it might have been myself on occasion)* forgot to set the flag to `false` again when the method returns early from execution.

Take the following scenario as an example:

```csharp
private async Task PrintAddressAsync()
{
    IsBusy = true;

    if (Copies < 1) return;

    await Task.Delay(TimeSpan.FromSeconds(2));

    OnPrintAddress?.Invoke(FullAddress);

    IsBusy = false;
}
```

Here, `IsBusy` would remain `true` although the method has already returned, if the value of `Copies` is smaller than `1`. The *ActivityIndicator* would keep spinning forever *(figuratively)*. This can be remedied in a couple of different ways, but none of them are pretty.

For example, we could set the `IsBusy` flag to `false` in multiple locations in our code, or we could decide to wrap that code, either by using [`try-finally`](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/try-finally) blocks or with an extra method which is executed between the two statements that update the `IsBusy` property.

**Option 1: Set flag in multiple locations**

```csharp
private async Task PrintAddressAsync()
{
    IsBusy = true;

    if (Copies < 1)
    {
        IsBusy = false;
        return;
    }

    await Task.Delay(TimeSpan.FromSeconds(2));

    OnPrintAddress?.Invoke(FullAddress);

    IsBusy = false;
}
```

This is ugly and error-prone, because we may easily forget to add the required statements to *all* possible code branches that return early from execution.

**Option 2: Use a** `try-finally` **block**

```csharp
private async Task PrintAddressAsync()
{
    try
    {
        IsBusy = true;

        if (Copies < 1) return;

        await Task.Delay(TimeSpan.FromSeconds(2));

        OnPrintAddress?.Invoke(FullAddress);
    }
    finally
    {
        IsBusy = false;
    }
}
```

This solution is abusing `try-finally` blocks for non-intended purposes, but it will work.

> **Note:** Usually, you would use a `finally` block to clean up resources

**Option 3: Introduce a separate method**

```csharp
private async Task PrintAddressAsync()
{
    IsBusy = true;

    await PrintAsync();

    IsBusy = false;
}

private async Task PrintAsync()
{
    if (Copies < 1) return;

    await Task.Delay(TimeSpan.FromSeconds(2));

    OnPrintAddress?.Invoke(FullAddress);
}
```

This is by far the best option when using flags, but it's still not pretty having to deal with several different busy flags in more elaborate ViewModels.

### Introducing AsyncRelayCommand

There is a solution to this and it's called [`AsyncRelayCommand`](https://learn.microsoft.com/dotnet/api/communitytoolkit.mvvm.input.asyncrelaycommand?view=win-comm-toolkit-dotnet-7.0).

The `[RelayCommand]` attribute of the MVVM Source Generators will generate different types of commands for us depending on the method signature.

When using a `void` method it will create a regular `RelayCommand`, but when the return type is an `async Task`, for example, it will actually generate an `AsyncRelayCommand` for us:

```csharp
//this will create a RelayCommand called "PrintAddressCommand"
[RelayCommand]
private void PrintAddress() {} 

//this will create an AsyncRelayCommand called "PrintAddressCommand"
[RelayCommand]
private async Task PrintAddressAsync() {}
```

> **Important:** When using `async` methods, it's common practice to use the **"Async"** suffix for the method name, e.g. `PrintAddressAsync()`. However, the Source Generators will recognize the suffix and remove it from the command name, so the command will still be called `PrintAddressCommand` (instead of `PrintAddressAsyncCommand`).

This is splendid, because the `AsyncRelayCommand` comes with its own type of busy flag in the form of a property called `IsRunning`. We can use this property instead of implementing our own `IsBusy` property. All we need to do is change the bindings of the *ActivityIndicator* from `IsBusy` to `PrintAddressCommand.IsRunning`:

```xml
<ActivityIndicator
  IsVisible="{Binding PrintAddressCommand.IsRunning}"
  IsRunning="{Binding PrintAddressCommand.IsRunning}"/>
```

> **Note:** Buttons in .NET MAUI automatically use the `IsRunning` flag when their `Command` property is bound to an asynchronous command. This is useful, because the button will be disabled until the command finishes execution.

We don't need to set *any* busy flags in the ViewModel anymore:

```csharp
[RelayCommand]
private async Task PrintAddressAsync()
{
    if (Copies < 1) return;

    await Task.Delay(TimeSpan.FromSeconds(2));

    OnPrintAddress?.Invoke(FullAddress);
}
```

👋 Goodbye, busy flags - `AsyncRelayCommand` FTW! I love it! 🤩

## Conclusions and next steps

Writing clean and maintainable ViewModels has never been easier thanks to the Source Generators of the MVVM Community Toolkit. We can still write exactly the same kind of logic like we did before while saving loads of valuable time and tremendously reducing the risk of bugs.

Source Generators can help you with decreasing the amount of boilerplate code and make ViewModels much more legible and comprehensible, provided you have a basic understanding of the MVVM pattern.

It's easier than ever to quickly write up a ViewModel with many different properties and set up commands and bindings with busy indicators without sacrificing any of the flexibility of manually implementing the `INotifyPropertyChanging` and `INotifyPropertyChanged` interfaces.

I hope you're just as excited as I am about this major development in the .NET realm. James Montemagno has recently summarized these amazing features of the MVVM Community Toolkit in another great [YouTube video](https://www.youtube.com/watch?v=9vvm_-YveTs) which is definitely worth checking out, as well.

If you enjoyed this blog post, then follow me on [**LinkedIn**](https://www.linkedin.com/in/jewerspeters), subscribe to this [**blog**](https://hashnode.com/@ewerspej) and star the [**GitHub**](https://github.com/ewerspej/maui-samples) repository for this post so you don't miss out on any future posts.
