使用 CommunityToolkit.Mvvm 构建应用

mindtian 发布于 24 天前 215 次阅读


AI 摘要

写 MVVM,你还在为冗长的属性声明、命令绑定代码头疼吗?明明只是想联动几行 UI,却得手写上百行样板逻辑。为什么模式本应让开发更优雅,现实却让人生畏?CommunityToolkit.Mvvm,号称“轻量高效”,却只需一个简单注解,就能替你瞬间生成那些烦人的重复代码。这一切究竟是如何做到的?背后的机制是否可靠?如果这样的简化真能成立,传统的写法是不是都白费力气了?带着这些疑问,让我们拆解 MVVM 的 “自动魔法源泉”。

1. 引言

MVVM【1】 是什么?

MVVM 是一种软件架构模式【2】,它的核心目标是将用户界面【3】的开发与业务逻辑【4】和数据处理【5】的开发分离开来。

2. 基本概念

MVVM 模式由三个组件组成:

2.1. Model(模型)

  • 负责应用程序的数据和业务逻辑。
  • 它完全不知道 View 和 ViewModel 的存在,它只是一个纯粹的数据和逻辑层,可以被任何部分复用。

2.2. View(视图)

  • 负责应用程序的 UI 部分。

2.3. ViewModel(视图模型)

  • 从 Model 中获取原始数据,并处理、转换为 View 需要的格式。

3. 它们是如何协同工作的?

MVVM 的运作核心是数据绑定【6】和命令【7】

4. CommunityToolkit.Mvvm 是什么?

它是一个由微软官方维护、开源【8】、高性能、平台无关【9】的 MVVM 工具库。

它的核心目标是:利用 C#【10】 的特性和编译器技术【11】,最大限度减少编写 MVVM 模式时所需的 "样板代码【12】"。

安装 :

通过 NuGet 包管理器【13】安装(视图 -> 其它窗口 -> 程序包管理控制台)

Install-Package CommunityToolkit.Mvvm【14】

也可通过右击解决方案,选择管理解决方案的 NuGet 程序包进行安装

然后,将你的 ViewModel 继承自 ObservableObject【15】 类。

public class MainViewModel : ObservableObject
{
}

5. 核心组件

5.1. [ObservableProperty] - 一行搞定属性绑定

它是如何工作的?

当我们在一个私有字段上标记 [ObservableProperty],源生成器【16】就会在编译时自动为我们创建一个公共属性(字段名 _name 会变成属性名 Name),并在这个属性的 set 访问器中内置了完整的 SetProperty【17】(包含变更检查和 OnPropertyChanged【18】 通知)逻辑。

示例:

手动实现:

public class MyViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private string _name;
    public string Name
    {
        get => _name;
        set
        {
            if (_name != value)
            {
                _name = value;
                OnPropertyChanged(nameof(Name));
            }
        }
    }

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

使用 CommunityToolkit.Mvvm 后的写法:


using CommunityToolkit.Mvvm.ComponentModel;

public partial class MyViewModel : ObservableObject
{
    [ObservableProperty]
    private string _name; 
}

5.2. [RelayCommand] - 简化命令绑定

它是如何工作的?

在一个方法上标记 [RelayCommand],源生成器会自动为我们生成一个 ICommand【19】 类型的属性(方法名 Submit 会变成命令名 SubmitCommand),并帮我们完成 new RelayCommand【20】(...) 的所有初始化工作。通过 CanExecute【21】 参数,还可以轻松地将一个判断方法关联到命令上,以控制 UI 元素的可用状态

示例:

手动实现:

public class MyViewModel : ViewModelBase
{
    public ICommand MyCommand { get; }

    public MyViewModel()
    {
        MyCommand = new RelayCommand(ExecuteMyCommand, CanExecuteMyCommand);
    }

    private void ExecuteMyCommand()
    {
        // ... 命令的执行逻辑 ...
    }

    private bool CanExecuteMyCommand()
    {
        // ... 判断命令是否可执行的逻辑 ...
        return true;
    }
}

使用 CommuityToolkit.Mvvm 的写法:

using CommunityToolkit.Mvvm.Input;

public partial class MyViewModel : ObservableObject
{
    [RelayCommand(CanExecute = nameof(CanGreetUser))]
    private void GreetUser(string userName)
    {
        // ... 执行逻辑 ...
        StatusText = $"Hello, {userName}!";
    }

    private bool CanGreetUser(string userName)
    {
        return !string.IsNullOrEmpty(userName);
    }
    
    [ObservableProperty]
    private string _statusText;
}

通过 CommunityToolkit.Mvvm,我们能够以更少的样板代码实现清晰的 MVVM 架构,使开发体验更高效。

CommunityToolkit.MVVM 官方文档