WPF MVVM框架 - CommunityToolkit.Mvvm 使用简介

255

WPF 的 CommunityToolkit.Mvvm(简称 MVVM Toolkit)是微软官方推出的轻量级 MVVM 框架,旨在简化 MVVM 模式在 WPF、UWP、WinUI 等应用中的实现。它通过 源代码生成器 和简洁的 API 减少样板代码,提高开发效率。

主要特性

轻量且高效

基于现代 C# 特性(如 partial class 和 Source Generators),减少手动编写的代码量。

强类型通知

自动生成属性通知逻辑,避免手写 INotifyPropertyChanged 实现。

命令简化

提供 RelayCommand 和 AsyncRelayCommand,简化命令绑定。

依赖注入支持

支持通过 Ioc 类实现简单的依赖注入。

消息机制

提供 Messenger 实现组件间松耦合通信。

安装使用

通过 NuGet 安装包:

Install-Package CommunityToolkit.Mvvm

核心组件

1. ObservableObject

ViewModel 的基类,自动实现 INotifyPropertyChanged 接口。

    using CommunityToolkit.Mvvm.ComponentModel;

    public partial class MyViewModel : ObservableObject
    {
        [ObservableProperty]
        private string _name; // 自动生成 public 属性 Name,并在赋值时触发 PropertyChanged 事件
    }

    // OnPropertyChanged() 通知UI属性值更改
    public class MainWindowViewModel : ObservableObject
    {
        public string? userName;
        public string? UserName { get { return userName; } set { userName = value; OnPropertyChanged(); } }

        public string? password;
        public string? Password { get { return password; } set { password = value; OnPropertyChanged(); } }

        private string? message;
        public string? Message { get { return message; } set { message = value; OnPropertyChanged(); } }
    }

2. RelayCommand

简化命令绑定,支持同步和异步操作。

using CommunityToolkit.Mvvm.Input;

public partial class MyViewModel : ObservableObject
{
    [RelayCommand]
    private void Submit()
    {
        // 执行提交逻辑
    }

    [RelayCommand(CanExecute = nameof(CanLoadData))]
    private async Task LoadDataAsync()
    {
        // 异步加载数据
    }

    private bool CanLoadData() => !IsBusy;
}

    public class MainWindowViewModel : ObservableObject
    {
        // 在ViewModel中定义命令
        public RelayCommand LoginCommand { get; set; }

        public MainWindowViewModel()
        {
            LoginCommand = new RelayCommand(Login);
        }

        public void Login()
        {
            MessageBox.Show("点击了登录");

            // TO DO: 登录逻辑
            // ...

            Message = "登录成功";
            UserName = "";
            Password = "";

            // 发送消息
            WeakReferenceMessenger.Default.Send("123", "login-cussess");
        }
    }

3. Messenger

跨组件消息传递(发布-订阅模式)。

// 定义消息
public class LoginSuccessMessage { }

// 发送消息
Messenger.Send(new LoginSuccessMessage());

// 接收消息
Messenger.Register<LoginSuccessMessage>(this, (recipient, message) => 
{
    // 处理消息
});

    public MainWindow()
    {
        InitializeComponent();

        this.DataContext = new MainWindowViewModel();

        // 接收消息
        WeakReferenceMessenger.Default.Register<string, string>(this, "login-cussess", (s, e) =>
        {
            MessageBox.Show("登录成功");
        });
    }


    public class MainWindowViewModel : ObservableObject
    {
        public string? userName;
        public string? UserName { get { return userName; } set { userName = value; OnPropertyChanged(); } }

        public string? password;
        public string? Password { get { return password; } set { password = value; OnPropertyChanged(); } }

        private string? message;
        public string? Message { get { return message; } set { message = value; OnPropertyChanged(); } }

        // 在ViewModel中定义命令
        public RelayCommand LoginCommand { get; set; }

        public MainWindowViewModel()
        {
            LoginCommand = new RelayCommand(Login);
        }

        public void Login()
        {
            MessageBox.Show("点击了登录");

            // TO DO: 登录逻辑
            // ...

            Message = "登录成功";
            UserName = "";
            Password = "";

            // 发送消息
            WeakReferenceMessenger.Default.Send("123", "login-cussess");
        }
    }

4. Ioc 依赖注入

简易的依赖注入容器。

// 注册服务
Ioc.Default.ConfigureServices(services => 
{
    services.AddSingleton<ILogger, FileLogger>();
});

// 获取服务
var logger = Ioc.Default.GetService<ILogger>();

基础使用示例

ViewModel 实现

public partial class MainViewModel : ObservableObject
{
    [ObservableProperty]
    private string _userName;

    [ObservableProperty]
    private int _count;

    [RelayCommand]
    private void IncrementCount()
    {
        Count++;
    }

    [RelayCommand(CanExecute = nameof(CanResetCount))]
    private void ResetCount()
    {
        Count = 0;
    }

    private bool CanResetCount => Count > 0;
}

<Window DataContext="{Binding MainViewModel}">
    <StackPanel>
        <TextBox Text="{Binding UserName, UpdateSourceTrigger=PropertyChanged}"/>
        <TextBlock Text="{Binding Count}"/>
        <Button Content="Increment" Command="{Binding IncrementCountCommand}"/>
        <Button Content="Reset" Command="{Binding ResetCountCommand}"/>
    </StackPanel>
</Window>

高级功能

嵌套属性通知

使用 NotifyPropertyChangedFor 特性通知关联属性:

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FullName))]
private string _firstName;

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FullName))]
private string _lastName;

public string FullName => $"{FirstName} {LastName}";

异步命令

使用 AsyncRelayCommand 处理异步操作

[RelayCommand]
private async Task LoadDataAsync()
{
    await Task.Delay(1000);
    // 加载数据
}

验证支持

结合 DataAnnotation 或自定义逻辑实现输入验证

最佳实践

代码结构:将 ViewModel 放在独立项目或文件夹(如 ViewModels)中。

命名规范:私有字段使用下划线前缀(如 _userName),生成的公共属性名自动转为 UserName。

解耦:通过 Messenger 实现组件间通信,避免直接引用。

其他MVVM框架

比如Prism或MVVM Light