
CommunityToolkit.Mvvm(MVVM 工具包)是微软把之前的Microsoft.Toolkit.Mvvm复活后的一个项目,最早的时候还在研究ReactiveX,不过在发现微软复活了这个老项目,并且还有源生成器的这种新特性后,直接转投研究MVVM 工具包了
代码
先来个简单的例子演示一下这个包的几个小功能
比如我现在又个小项目,下面是它的部分源码
MainWindow.xaml的Window里,只添加一个StackPanel
<StackPanel VerticalAlignment="Center">
<TextBlock Text="{Binding Text}" />
<TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
新建个MainWindowModel.cs拿来放要被绑定的数据
internal class MainWindowModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
private string _text = "Hello World!";
public string Text
{
get => _text;
set
{
_text = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Text)));
}
}
}
MainWindow.xaml.cs的InitializeComponent();下面加一行绑定
this.DataContext = new MainWindowModel();
实现了什么功能

这一小段代码,简单的将一个TextBlock和TextBox的Text属性的值,都绑定到了Text这个变量上面:
TextBox的Text属性的值被更改Text被赋予新的值,调用set访问器set访问器在更新_text值后,触发PropertyChanged.InvokeTextBlock的Text属性的值被更新
在开始之前,首先要在
nuget里装上CommunityToolkit.Mvvm这个包
要使用这个功能,我们先要把MainWindowModel类改成分布类,只需要在声明的地方加个partial前缀就好
[INotifyPropertyChanged]
internal partial class MainWindowModel
在最上方,引用一下CommunityToolkit.Mvvm的类
//using System.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
ObservableProperty自动生成可观察属性
我们可以直接用ObservableProperty,于是MainWindowModel类的代码变成了这样:
[INotifyPropertyChanged]
internal partial class MainWindowModel
{
[ObservableProperty]
private string _text = "Hello World!";
}
这里的源生成器会自动按大驼峰命名规范来转换你的变量名,如
lowerCamel、 、_lowerCamel或m_lowerCamel都会被转换为UpperCamel,并且将被声明为public以便使用
可以看到代码量大大减少了,当代码编译时,会自动编译成下面的样子(来自ILSpy的反编译结果,我精简掉了很多代码,以便大家可以清晰看懂):
internal class MainWindowModel : INotifyPropertyChanged
{
private string _text = "Hello World!";
public string Text
{
get
{
return _text;
}
set
{
if (!EqualityComparer<string>.Default.Equals(_text, value))
{
_text = value;
OnPropertyChanged(__KnownINotifyPropertyChangedArgs.Text);
}
}
}
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
this.PropertyChanged?.Invoke(this, e);
}
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
}
可以看到,会精简掉很大部分的代码,让逻辑更清晰,同时减轻工作量
依赖其他值的属性
比如我们在MainWindowModel类添加另一个属性OtherText:
public string OtherText
{
get
{
return "Other:" + _text;
}
}
然后让TextBlock的绑定更改为它:
<TextBlock Text="{Binding OtherText}" />
这时我们知道,当Text变化后,OtherText也应该变化,那么如何触发OtherText的更新呢?
我们可以使用NotifyPropertyChangedFor,像这样:
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(OtherText))]
private string _text = "Hello World!";
这样写之后,当Text变化后,会通知OtherText也变化了,从而实现及时的更改:

绑定命令
MVVM 工具包的源生成器同样可以绑定命令,比如我们在MainWindowModel类添加一个函数Hello,使用RelayCommand即可简便的实现该功能
[RelayCommand]
private void Hello()
{
Text = "Hello!";
}
RelayCommand会自动生成一个名为HelloCommand的函数用于绑定,我们可以在StackPanel内添加一个Button来测试这个功能
<Button Command="{Binding HelloCommand}" Content="123" />
点击按钮后,可以看到功能正常

绑定异步命令
同时我们绑定的命令也可以是异步的,可以把函数Hello改成下面这样,继续测试
[RelayCommand]
private async void Hello()
{
for (int i = 1; i <= 10; i++)
{
Text = $"wait {i}";
await Task.Delay(500);
}
}
这样写不会卡住UI线程,效果如下:

其他功能
其他还有很多功能,这里就不一一列举了,大家可以前往MVVM 工具包官方文档查看