908 字
5 分钟
[.NET/WPF] 如何使用 CommunityToolkit.Mvvm
2023-05-12

CommunityToolkit.Mvvm 包(又名 MVVM 工具包,以前称为 Microsoft.Toolkit.Mvvm)是一个现代、快速和模块化的 MVVM 库。 它是 .NET Community Toolkit 的一部分,并围绕以下原则构建:

  • 独立于平台和运行时 - .NET Standard 2.0、.NET Standard 2.1 和 .NET 6 (与 UI 框架无关)
  • 易于上手和使用 — 对应用程序结构或编码范例(“MVVM”之外)没有严格要求,即灵活使用。
  • 可选 - 自由选择要使用的组件。
  • 引用实现 - 精益和高性能,为基类库中包含的接口提供实现,但缺乏直接使用它们的具体类型。

可观察对象 / ObservableObject#

在 WPF 中, 写出 MVVM 设计模式的程序, 自然需要进行前台与后台数据的绑定, 而在原生实现中, 编写一个可绑定的类, 并且编写该类中可绑定的成员, 是非常麻烦的一件事情。 你需要手动在值变更的时候, 引发 “PropertyChanged” 事件, 大概的代码会像这样:

public class MainViewModel : INotifyPropertyChanged
{
    private string windowTitle = "Toturial App";
    public string WindowTitle
    {
        get => windowTitle;
        set
        {
            windowTitle = value;
            NotifyPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged; 

    protected void NotifyPropertyChanged([CallerMemberName] string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

像这样, 每一个属性都需要编写一个对应的字段, 然后手动编写 getter, setter, 并在 setter 中进行属性变更的通知,显然, 非常麻烦。

在 CommunityToolkit.Mvvm 中, 提供了用于生成这些重复性代码的源生成器, 我们只需要简单的在需要的地方加上一些特性, 就可以实现这些复杂的东西了。 例如, 上述代码在 CommunityToolkit.Mvvm 中, 代码是这样的:

[ObservableObject]
public partial class MainViewModel
{
    [ObservableProperty]
    private string windowTitle = "Toturial App";
}

为所需的 ViewModel 添加 ObservableObject 特性, 利用分布类, 他会自动生成该类型对 INotifyPropertyChanged 的实现。 而打上了 ObservableProperty 特性的字段, 源生成器会自动生成该字段名称转换为大驼峰之后的一个属性, 并在属性定义中包含对属性变更的通知逻辑。

简单来讲, 我们不需要写那么复杂的逻辑了。 只需要为可观察的类型打上 ObservableObject, 为可观察的属性打上 ObservableProperty, 其余的, 都会自动生成。

RelayCommand / 中继指令#

同样的, 在原生 WPF 中, 想要定义一个指令, 也是非常麻烦的一件事。 你需要为指令专门写一个类, 并实现 ICommand 接口。 在这个接口中分别包含了判断指令是否能够执行,执行指令的方法,以及一个用于通知 “指令可执行性变更” 的事件。

public class MyCommand : ICommand
{
    public bool CanExecute(object parameter)
    {
        // 这里写判断命令是否可执行的逻辑
    }

    public void Execute(object parameter)
    {
        // 这里是命令执行的逻辑
    }

    // 这里是用于通知指令可执行性变更的事件
    public event EventHandler? CanExecuteChanged;
}

但是很多时候, 我们的指令只是一些简单的逻辑, 为一个简单逻辑编写一个类, 未免有些太麻烦了。 于是 CommunityToolkit.Mvvm 中为我们提供了一个特性:RelayCommand。

当为一个方法打上 RelayCommand 标记的时候, CommunityToolkit.Mvvm 会在该方法所在的类下生成一个对应的 Command, 你可以在界面上直接绑定到这个 Command, 而不需要自己手动编写一个 Command 类。

public partial class MainWindow
{
    public MainWindow()
    {

        // 将绑定上下文设为自身
        DataContext = this;
        InitalizeComponents();
    }

    // 这里会生成一个 ShowMessageCommand 属性
    [RelayCommand]
    public void ShowMessage()
    {
        MessageBox.Show("Hello world!");
    }
}
<Window ...>
    <Grid>
        <StackPanel>
            <!--直接绑定到后台的 ShowMessageCommand-->
            <Button Content="Click Me" Command="{Binding ShowMessageCommand}"/>
        </StackPanel>
    </Grid>
</Window>
[.NET/WPF] 如何使用 CommunityToolkit.Mvvm
https://slimenull.com/posts/20230512125059/
作者
SlimeNull
发布于
2023-05-12
许可协议
CC BY-NC-SA 4.0