This issue's Microsoft MVP Lab researcher -- Chen Jinhua, Microsoft MVP (Windows Development direction), focuses on .NET development and has more than ten years of client development experience. Passionate about blogging and sharing experiences with WPF, UWP, and Azure DevOps.
1. About MVVM Toolkit
The .NET Community Toolkit is a collection of helper classes and APIs for all .NET developers, independent of any particular UI platform. It has released version 8.0.0 preview1, which includes the following components migrated from the Windows Community Toolkit:
• CommunityToolkit.Common
• CommunityToolkit.Mvvm
• CommunityToolkit.Diagnostics
• CommunityToolkit.HighPerformance
Among them, CommunityToolkit.Mvvm, also known as MVVM Toolkit, is a modern, fast and modular MVVM library. It contains a Source Generators component: MVVM Toolkit source generators. This article will describe how it helps developers write MVVM code quickly.
2. MVVM Toolkit source generators
Source Generators is a C# compiler feature that enables C# developers to check when compiling user code and dynamically generate new C# source files to add to the user's compilation. In this way, your code can run during compilation and check your program to generate additional source files that are compiled with the rest of your code.
For developers of the MVVM platform, Source Generators are a long-awaited new feature. After all, in the MVVM pattern, developers need to write additional template code for many commands and properties. So far, Microsoft and other developers have come up with many different solutions to ease the burden of this extra code, and Source Generators looks like a better one. The MVVM Toolkit has begun work on this, and the 8.0 version has been further enhanced. Now the MVVM Toolkit source generators are an incremental generator, and the performance will be improved a lot.
The following will briefly explain how to use the code of the MVVM Toolkit source generators commands and properties.
3. How to generate the code for the command
In the MVVM pattern, the way the command is written is a bit annoying. This is the usual way of writing in the MVVM Toolkit:
private IRelayCommand _displayCommand;
IRelayCommand DisplayCommand => _displayCommand ??= new RelayCommand(new Action(Display), () => HasName);
private void Display()
{
}
First, there is a lot of code. In addition, should _displayCommand and DisplayCommand and Display() be written together, or should they be placed in different positions in the code according to the order of fields, properties, and functions? Or simply use the Partial class to put them in different files?
With source generators there is no such annoyance, the definition of the command can be simplified to this:
[ICommand(CanExecute = nameof(HasName))]
private void Display()
{
}
By adding ICommandAttribute, source generators can correctly generate DisplayCommand and corresponding initialization code according to the function name of Display(). In addition, you can also specify through its CanExecute property to associate the ICommand's CanExecute to the corresponding property.
4. How to generate code for attributes
Properties also have the same troubles as commands. Generally speaking, properties in the MVVM pattern are written as follows:
private string name;
public string Name
{
get => name;
set => SetProperty(ref name, value);
}
It's actually okay, not too much. But what if:
private string _surname;
public string Surname
{
get
{
return _surname;
}
set
{
if (!EqualityComparer<string>.Default.Equals(_surnam
{
_surname = value;
OnPropertyChanged();
OnPropertyChanged(nameof(FullName));
OnPropertyChanged(nameof(HasName));
DisplayCommand.NotifyCanExecuteChanged();
}
}
}
public string FullName => $"{Name} {Surname}";
public bool HasName => !string.IsNullOrWhiteSpace(FullName);
At this time, the role of source generators can be obvious, because it only needs the following code to automatically generate the code equivalent to the above:
[ObservableProperty]
[AlsoNotifyChangeFor(nameof(FullName), nameof(HasName))]
[AlsoNotifyCanExecuteFor(nameof(DisplayCommand))]
private string _surname;
public string FullName => $"{Name} {Surname}";
public bool HasName => !string.IsNullOrWhiteSpace(FullName);
As you can see from this code, there are three Attributes that work:
- ObservableProperty: Automatically generate a corresponding property for the _name property.
- AlsoNotifyChangeFor: The PropertyChanged events of the FullName and HasName properties are triggered at the same time when the property value is modified.
- AlsoNotifyCanExecuteFor: NotifyCanExecuteChanged() is notified to DisplayCommand to execute its NotifyCanExecuteChanged() when the property value is modified.
5. How to inject into an existing class
In general, MVVM Toolkit source generators need to be used in ObservableObject derived classes, for example:
public partial class TestModel: ObservableObject
But if your class already inherits other classes, the MVVM Toolk source generators also allow you to use its functionality by adding the INotifyPropertyChangedAttribute with the following code:
[INotifyPropertyChanged]
public partial class TestModel: Behaviour
The INotifyPropertyChangedAttribute automatically generates code that implements INotifyPropertyChanged without changing the base class. Unfortunately, INotifyPropertyChangedAttribute can only be used in classes that do not implement the INotifyPropertyChanged interface, that is, the following code cannot be compiled:
[INotifyPropertyChanged]
public partial class TestModel: ObservableObject
6. The result of using source generators
Using source generators can greatly reduce the code, and the following figure visually shows the reduced amount of code.
If you need to view the auto-generated code, you can view it in the analyzer's
Find in the CommunityToolkit.Mvvm.SourceGenerators node:
7. Some small problems
MVVM Toolkit source generators can refactor your code, but at what cost?
First, although the MVVM Toolkit source generators support .NET Standard 2.0, some features require C# 8.0 or higher, so you may see this error when compiling:
The source generator features from the MVVM Toolkit require consuming projects to set the C# language version to at least C# 8.0
The solution is to add this section to the PropertyGroup node of the project file specifying the C# version:
<LangVersion>9.0</LangVersion>
Additionally, the MVVM Toolkit source generators also require Visual Studio 2022 to work.
One more thing, I haven't found a way to annotate the generated properties, which is deadly for some hard-to-understand properties, and have to go back to the traditional way of dealing with such properties.
Finally, without CodeLens, it is impossible to intuitively see the reference, modification and other information of attributes, which is not very easy to use.
In general, MVVM Toolkit source generators can help customers reduce a lot of code work, and source generators have huge advantages in terms of code volume, maintainability, and readability. But at this stage, there are still many small problems in its use, and it cannot completely replace the native writing method. But it's a tool that fits the 80/20 principle: it allows users to solve 80% of the problems with 20% of the investment. So developers can try this tool in new projects to improve development efficiency.
Both the .NET Community Toolkit and the MVVM Toolkit are open source projects, so you can also submit your feedback and code in its repository.
For more information, please refer to Github or other documents:
https://github.com/CommunityToolkit/dotnet
https://github.com/CommunityToolkit/dotnet/releases/tag/v8.0.0-preview1
https://docs.microsoft.com/zh-cn/windows/communitytoolkit/mvvm/introduction
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。