WPF CommunityToolKit.MVVM使用

katekate 发布于 29 天前 32 次阅读


在使用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!

此作者没有提供个人介绍。
最后更新于 2026-01-04