在使用C#开发软件的时候,难免会遇到需要进行前后端分离的情况。自行实现INotification接口非常麻烦,这时候就要用到微软官方给出的简化方法了。
一、CommunityToolKit.MVVM的介绍
CommunityToolkit.Mvvm(以前称为 Microsoft.Toolkit.Mvvm)是 .NET 社区工具包(.NET Community Toolkit)中的一部分,是一个轻量级、现代、高性能且完全基于源代码生成(Source Generators)和 C# 最新特性的 MVVM(Model-View-ViewModel)框架。它由微软发起并维护,现由 .NET 基金会下的社区团队共同开发,适用于 WPF、WinUI、MAUI、Uno Platform、Avalonia 等支持 MVVM 模式的 .NET UI 框架。
二、使用方法
2.1 使用前提
需要使用.NET Standard 2.0+或者.NET 6+运行时。CommunityToolKit.MVVM以Nuget包的形式发行,使用前需要加入解决方案的Nuget包。
2.2 使用方法
2.2.1 ObservableObject
替代OnPropertyChanged()写法:
using CommunityToolkit.Mvvm.ComponentModel;
public partial class MainViewModel : ObservableObject
{
[ObservableProperty]
private string name;
[ObservableProperty]
private int age;
}
编译后自动等同于:
public string Name
{
get => name;
set => SetProperty(ref name, value);
}
public int Age
{
get => age;
set => SetProperty(ref age, value);
}
2.2.2 RelayCommand
在CommunityToolKit.MVVM中,不需要手动创建RelayCommand或者DelegateCommand。示例:
[RelayCommand]
private void Save()
{
// 执行保存逻辑
Console.WriteLine($"Saving {Name}...");
}
会自动生成
public IRelayCommand SaveCommand { get; }
在前端XAML代码中绑定:
<Button Command="{Binding SaveCommand}" Content="Save" />
需要带参数时,绑定使用:
<Button Command="{Binding DeleteCommand}" CommandParameter="Item1" />
参数类型会自动推断。
使用异步命令(AsyncRelayCommand):
[RelayCommand]
private async Task LoadDataAsync()
{
await Task.Delay(1000);
Name = "Loaded!";
}
前端绑定按钮:
<Button
Command="{Binding LoadDataCommand}"
IsEnabled="{Binding LoadDataCommand.IsRunning, Converter={StaticResource InverseBoolConverter}}"
Content="Load" />
注意:异步方法的返回值必须是Task。
2.2.3 属性变更联动(OnPropertyChanged)
[ObservableProperty]
private string firstName;
[ObservableProperty]
private string lastName;
[ObservableProperty]
private string fullName;
partial void OnFirstNameChanged(string value)
{
FullName = $"{value} {LastName}";
}
partial void OnLastNameChanged(string value)
{
FullName = $"{FirstName} {value}";
}
2.2.4 Messenger组件间通信
定义消息类:
public record UserUpdatedMessage(string UserId);
发送消息:
// 在某个 ViewModel 中
WeakReferenceMessenger.Default.Send(new UserUpdatedMessage("123"));
接受消息:
public partial class AnotherViewModel : ObservableRecipient
{
public AnotherViewModel()
{
// 注册接收
Messenger.Register<UserUpdatedMessage>(this, (r, m) =>
{
// 处理消息
Console.WriteLine($"User {m.UserId} updated!");
});
}
// 可选:重写 IsActive 来控制是否接收
protected override bool IsActive { get; set; } = true;
}
三、应用示例
下面这个项目中有一个MainView,MainViewModel:

首先需要绑定View和ViewModel,编辑MainWindow.xaml:
xmlns:local="clr-namespace:TestMVVM.ViewModels"
在文件的下面还需要添加:
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
这部分将这个View绑定到ViewModel中。
在该界面中放置了一个按钮:

前台代码:
<Window x:Class="TestMVVM.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestMVVM.ViewModels"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<Button Content="Test" Height="50" Width="100" Command="{Binding TestButtonCommand}"/>
</Grid>
</Window>
MainViewModel中:
using System.Windows;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace TestMVVM.ViewModels
{
public partial class MainViewModel:ObservableObject
{
[RelayCommand]
private void TestButton()
{
MessageBox.Show("Button Clicked!");
}
}
}
该部分实现了一个RelayCommand,绑定到前台的Button控件的Command。
运行结果:点击按钮,弹出对话框提示Button Clicked!

