Announcing .NET Community Toolkit v8.0.0 Preview 3

Sergio Pedri

As we’re getting close to the official launch of the new .NET Community Toolkit, we’re happy to announce that the third preview of the upcoming 8.0.0 release is now live! As is the case with every new public preview, there’s lots of new features to explore, as well as several improvements and bug fixes. Once again, all changes were influenced by feedback received both by teams here at Microsoft using the Toolkit as well as other developers in our community. We’re so thankful to everyone that has contributed and is helping the .NET Community Toolkit get better every day! 🎉

As a small refresher, the 8.0.0 release will be the first release from the brand new .NET Community Toolkit repository, which will be the home of all our general .NET libraries going forward. Libraries in this new toolkit have no dependencies on any specific UI frameworks, so they can be used by all developers regardless of the framework or runtime they choose to work on their projects. These libraries multi-target .NET Standard 2.0 and .NET 6, so they can both support as many platforms as possible and be optimized for best performance when used on newer runtimes. The libraries in the .NET Community Toolkit include:

NOTE: the docs links are still in the process of migrating to the new “CommunityToolkit” directory, and the API references still refer to the previous “Microsoft.Toolkit” namespace for now. Refer to our previous blog post for more info about this change in namespace and package identity, and this other blog post to learn more about the naming change. A preview of the new docs is available here.

Here is a breakdown of the main changes you can expect in this new release.

🤖 MVVM Toolkit source generators

This new release of the MVVM Toolkit keeps expanding the source generator features, which were introduced in our previous preview release (see more details in this blog post. These APIs are meant to greatly reduce the necessarily boilerplate when working with MVVM, with helpers ranging from observable properties to commands, and much more. Here is a breakdown of the new features that have been added since Preview 1.

Partial property changed methods

When using [ObservableProperty] to generate observable properties, the MVVM Toolkit will now also generate two partial methods with no implementations: On<PROPERTY_NAME>Changing and On<PROPERTY_NAME>Changed. These methods can be used to inject additional logic when a property is changed, without the need to fallback to using a manual property. Note that because these two methods are partial, void-returning and with no definition, the C# compiler will completely remove them if they are not implemented, meaning that when not used they will simply vanish and add no overhead to the application 🚀

This is an example of how they can be used:

[ObservableProperty]
private string name;

partial void OnNameChanging(string name)
{
    Console.WriteLine($"The name is about to change to {name}!");
}

partial void OnNameChanged(string name)
{
    Console.WriteLine($"The name just changed to {name}!");
}

Of course, you’re also free to only implement one of these two methods, or none at all.

From that snippet above, the source generator will produce code analogous to this:

public string Name
{
    get => name;
    set
    {
        if (!EqualityComparer<string>.Default.Equals(name, value))
        {
            OnNameChanging(value);
            OnPropertyChanging();
            name = value;
            OnNameChanged();
            OnPropertyChanged();
        }
    }
}

partial void OnNameChanging(string name);

partial void OnNameChanged(string name);

Thanks to Fons Sonnemans for suggesting this feature! 🏆

Cancellation support for commands

A new property has been added to the [ICommand] attribute, which can be used to instruct the source generator to generate a cancel command alongside the original command. This cancel command can be used to cancel the execution of an asynchronous command.

This is an example of how they can be used:

[ICommand(IncludeCancelCommand = true)]
private async Task DoWorkAsync(CancellationToken token)
{
    // Do some long running work with cancellation support
}

From this small snippet, the generator will produce the following code:

private AsyncRelayCommand? doWorkCommand;

public IAsyncRelayCommand DoWorkCommand => doWorkCommand ??= new AsyncRelayCommand(DoWorkAsync);

ICommand? doWorkCancelCommand;

public ICommand DoWorkCancelCommand => doWorkCancelCommand ??= IAsyncRelayCommandExtensions.CreateCancelCommand(UpdateSomethingCommand);

This generated code, combined with the logic in the IAsyncRelayCommandExtensions.CreateCancelCommand API, allow you to just need a single line of code to have a command generated, notifying the UI whenever work has started or is running, with automatic concurrency control (the command is disabled by default when it is already running). The separate cancel command will be notified whenever the primary command starts or finishes running, and when executed will signal cancellation to the token passed to the method wrapped by the primary command. All of this, completely abstracted away and easily accessed with just a single attribute 🙌

Broadcast change support for generated properties

We’ve also added a new [AlsoBroadcastChange] attribute which can be used on generated observable property from a type that inherits from ObservableRecipient (or that is annotated with [ObservableRecipient]). Using it will generate a call to the Broadcast method, to send a message to all other subscribed component about the property change that just happened. This can be useful in scenarios where a property change from a viewmodel needs to also be notified to other components in the application (Suppose there is an IsLoggedIn boolean property which updates when a user signs in; this can notify and trigger some other components in the application to refresh with the broadcasted message).

It can be used as follows:

[ObservableProperty]
[AlsoBroadcastChange]
private string name;

And this will produce code analogous to this:

public string Name
{
    get => name;
    set
    {
        if (!EqualityComparer<string>.Default.Equals(name, value))
        {
            OnNameChanging(value);
            OnPropertyChanging();
            string oldValue = name;
            name = value;
            Broadcast(oldValue, value, nameof(Name));
            OnNameChanged();
            OnPropertyChanged();
        }
    }
}

This is yet another feature to augment generated properties and to ensure they can be used in almost all scenarios, without being forced to fallback to manual properties.

Thanks to Cliff V for suggesting this feature! 🏆

Improved diagnostics

One area that has received a lot of work for this new release is diagnostics. We want the MVVM Toolkit generators to help developers with clear error messages to both try to detect errors as early as possible when writing code and to make it easy to understand what’s wrong, and how to address the issue. There are some examples of new diagnostics that the MVVM Toolkit generators will emit in Preview 3:

  • MVVMTK0014: a field with [ObservableProperty] has a name that will cause the generated property name to clash with another existing property.
  • MVVMTK0015, MVVMTK0016: [AlsoNotifyChangeFor] or [AlsoNotifyCanExecuteFor] are used with a target property that doesn’t exist or is not valid.
  • MVVMTK0020: any of the attributes that depend on [ObservableProperty] (eg. [AlsoNotifyChangeFor]) are used on a field that is not annotated with [ObservableProperty].
  • MVVMTK0023: the [ICommand] is used multiple times on method overloads (or is incorrectly duplicated).

These are just some of the new diagnostics, but there are many more in the MVVM Toolkit. The goal here is to provide an easy developer experience, where the source generator guide developers to write code that is correct, and where invalid code is immediately detected before the app ever starts running. 🧠

NOTE: the source generators in the MVVM Toolkit require Roslyn 4.x in order to run. As such, VS2022 or another IDE with Roslyn 4.x support is required. Using the MVVM Toolkit on VS2019 or another older IDE is still supported, but the source generators will automatically be disabled there, so features relying on them will not be supported.

📃 Revamped observable grouped collections

This new release of the MVVM Toolkit also moves all the observable grouped collection types from the CommunityToolkit.Common package to CommunityToolkit.Mvvm, while also doing some major changes to improve the API surface and make it useful in more scenarios. These APIs are particularly useful when working with grouped items (eg. to display a list of contacts), and they now also include extensions to greatly facilitate common operations such as inserting an item in the right position within a group (using either the default comparer or an input one, and creating a new group as well if needed). You can see a full API breakdown in this tracking issue.

Here’s a GIF showcasing a simple contacts view from the MVVM Toolkit Sample App:

A grouped contacts list
An interactive grouped collection of contacts using the MVVM Toolkit collection APIs

Don’t forget to also check out our MVVM Toolkit Sample App to see the full source code!

⚙️ Other changes

There is so much more being included in this new release!

You can see the full changelog in the GitHub release page.

Get started today! 🎉

You can find all source code in our GitHub repo. The handwritten docs are available on the MS Docs website, and complete API references can be found in the .NET API browser website. If you would like to contribute, feel free to open issues or to reach out to let us know about your experience! To follow the conversation on Twitter, use the #CommunityToolkit hashtag. All your feedbacks greatly help in shape the direction of these libraries, so make sure to share them!

Happy coding! 💻

2 comments

Leave a comment

  • Max

    Why is this called community toolkit?

    That’s merely a type of software, but hardly a descriptive name for a specific piece of software.

    That’s like giving a book the title “book”. Like ok Sherlock, but what’s in it?