首页 > 其他分享 >WPF笔记13——CommunityToolKit.Mvvm

WPF笔记13——CommunityToolKit.Mvvm

时间:2024-12-30 12:30:18浏览次数:1  
标签:CommunityToolKit Mvvm ViewModel RelayCommand 命令 private WPF public

1、[ObservableProperty]标记

private字段上有 [ObservableProperty]标记,CommunityToolkit.Mvvm会自动给它生成一个对应的public属性,并在属性值改变时自动触发属性变更通知。

2、[ObservableObject]标记

ObservableObject类型实现了实现了INotifyPropertyChanged和INotifyPropertyChanging接口,这使得对象的属性变化可以被观察到,从而实现数据绑定和通知机制。

3、[RelayCommand]标记

在 CommunityToolkit.Mvvm 包中,RelayCommand 是一个实现了 ICommand 接口的类,用于在 MVVM 模式中处理命令。RelayCommand 允许你将一个方法绑定到一个按钮或其他触发器上,当触发器被激活时,这个方法就会被调用。RelayCommand 还支持可执行性的检查,即在某些条件下命令可以被执行。

手写mvvm代码:

public partial class MyViewModel : INotifyPropertyChanged
{ 
    private string _name;

    public string Name
    {
      get{return _name;}
      set{
            _name=value;
            this.RaiseNotifiedChanged(nameof(Name)); 
         } 
    }

    //DeletegateCommand是一个继承ICommand类的方法
    public DeletegateCommand MyCommand { get; }


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

    private bool CanExecuteCommand()
    {
        // 命令是否可以执行的逻辑
        return true;
    }


    public event PropertyChangedEventHandler? PropertyChanged;


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

    public MyViewModel ()
    {
       MyCommand = new DeletegateCommand(ExecuteCommand, ExecuteCommand); 
    }

}

使用CommunityToolkit.Mvvm.ComponentModel包后的代码

using CommunityToolkit.Mvvm.ComponentModel;

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


    public ICommand MyCommand { get; }

    public MyViewModel()
    {
        MyCommand = new RelayCommand(ExecuteCommand, CanExecuteCommand);
    }

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

    private bool CanExecuteCommand()
    {
        // 命令是否可以执行的逻辑
        return true;
    }

}

在上述代码中,CommunityToolkit.Mvvm会在编译时生成以下等效代码:

using CommunityToolkit.Mvvm.ComponentModel;

public partial class MyViewModel : ObservableObject
{
    private string _name;

    public string Name
    {
        get => _name;
        set => SetProperty(ref _name, value);
    }

    [RelayCommand] //[RelayCommand] 特性直接在方法上,这样可以自动生成一个以方法名加 Command 后缀的 RelayCommand
    private void ExecuteCommand()
    {
        // 命令执行的逻辑
    }
}

补充:

1、使用 [ObservableProperty] 和 [NotifyCanExecuteChangedFor] 特性

对于需要根据某个属性的值来决定命令是否可执行的情况,可以使用 [NotifyCanExecuteChangedFor] 特性。

这个特性允许我们指定一个命令,当指定的属性值变化时,会自动通知命令的 CanExecute 方法重新评估。

例如下面代码,当IsEnable属性发生变化时,ButtonClickCommand 的可执行性会自动更新

[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(ButtonClickCommand))]
private bool isEnable;

[RelayCommand(CanExecute = nameof(CanButtonClick))]
private void ButtonClick()
{
    // 命令执行的逻辑
}

private bool CanButtonClick() => IsEnable;

2、异步版本的RelayCommand

如果我们需要执行异步操作,可以使用异步版本的RelayCommand。

这样,我们可以在命令执行的方法中使用await,而不用担心阻塞UI线程。

例如下代码,允许我们在命令中执行异步操作,同时保持UI的响应性

[RelayCommand(CanExecute = nameof(CanButtonClick))]
private async Task ButtonClick()
{
    await Task.Delay(1500);
    // 命令执行的逻辑
}

3、命令添加参数

3.1、使用 [RelayCommand] 和 [RelayCommandParameter] 特性:

我们可以使用 [RelayCommand] 特性来自动创建命令,并使用 [RelayCommandParameter] 特性来指定命令的参数。

using CommunityToolkit.Mvvm.Input;

public class MyViewModel : ObservableObject
{
    [RelayCommand]
    [RelayCommandParameter]
    private void ExecuteCommand(string parameter)
    {
        // 使用参数执行命令
        Console.WriteLine($"Command executed with parameter: {parameter}");
    }
}

//在xaml中绑定命令 
//s:RelayCommand 标记扩展来绑定命令,这是 CommunityToolkit.Mvvm 源代码生成器提供的功能。
<Button Command="{s:RelayCommand ExecuteCommand}" 
        CommandParameter="Hello World" 
        Content="Click Me" />

**注意,配置 Source Generators: 确保我们的项目文件(.csproj)中包含了启用源代码生成器的配置。**
<PropertyGroup>
  <EnableSourceLink>false</EnableSourceLink>
  <EnableSourceControlManagerQueries>false</EnableSourceControlManagerQueries>
</PropertyGroup>

3.2、如果Button在DataGrid中,要传递的是DataGrid中对应行的对象

例如:

有一个 DataGrid 绑定到 List 数据源,并且每个 DataGrid 行中都有一个按钮;
我们可能希望点击按钮时传递当前行对应的 Student 对象到事件处理方法。

以下是实现这一功能的步骤:

step1、定义按钮的命令:

在 ViewModel 中,可以定义一个接受 Student 参数的命令。

public class MyViewModel : ObservableObject
{
    public ICommand StudentSelectedCommand { get; }

    public MyViewModel()
    {
        StudentSelectedCommand = new RelayCommand<Student>(OnStudentSelected);
    }

    private void OnStudentSelected(Student student)
    {
        // 这里处理学生对象
    }
}

step2、在 XAML 中绑定命令:

在 DataGrid 的按钮列中,可以使用 Button 的 Command 属性来绑定 ViewModel 中的命令,并使用 CommandParameter 来传递当前行的 Student 对象。

<DataGrid ItemsSource="{Binding Students}">
    <!-- 其他列定义 -->
    <DataGridTemplateColumn>
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <Button Command="{Binding RelativeSource={RelativeSource AncestorType=DataGrid}, Path=DataContext.StudentSelectedCommand}"
                        CommandParameter="{Binding}">
                    Click Me
                </Button>
            </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
</DataGrid>

step3、使用 RelativeSource 找到 ViewModel:

RelativeSource 用于找到当前按钮的祖先 DataGrid,然后通过 Path=DataContext 找到 ViewModel。这是因为 Button 本身的 DataContext 是当前行的 Student 对象,而我们需要命令的 DataContext 是 ViewModel。

step4、在 ViewModel 中处理命令:

当按钮被点击时,OnStudentSelected 方法会被调用,并且当前行的 Student 对象作为参数传递

这个过程还可以简化写成下面这样:

step1、定义 ViewModel:

在我们的 ViewModel 中,使用 [RelayCommand] 特性来定义一个命令。

using CommunityToolkit.Mvvm.Input;

public class MyViewModel : ObservableObject
{
    [RelayCommand]
    private void OnStudentSelected(Student student)
    {
        // 这里处理学生对象
    }
}

step2、在 XAML 中绑定命令:

在 DataGrid 的按钮列中,使用 s:RelayCommand 来绑定命令,并使用 DataGrid 的 DataContext 来传递当前行的 Student 对象。

s:RelayCommand 是一个标记扩展,它会自动为你创建一个 RelayCommand 实例,并绑定到 ViewModel 中的方法。ViewModel=DataContext 指定了命令的 ViewModel,而 s:RelayCommandParameter="{Binding}" 传递了当前行的 DataContext(即 Student 对象)作为命令的参数。

<DataGrid ItemsSource="{Binding Students}">
    <!-- 其他列定义 -->
    <DataGridTemplateColumn>
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <Button Content="Click Me"
                        s:RelayCommand="{s:RelayCommand OnStudentSelected, ViewModel=DataContext}"
                        s:RelayCommandParameter="{Binding}" />
            </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
</DataGrid>

step3、配置 Source Generators:

确保我们的项目文件(.csproj)中包含了启用源代码生成器的配置。

<PropertyGroup>
  <EnableSourceLink>false</EnableSourceLink>
  <EnableSourceControlManagerQueries>false</EnableSourceControlManagerQueries>
</PropertyGroup>

使用 CommunityToolkit.Mvvm 包后,我们不需要手动创建 RelayCommand 实例,也不需要在 ViewModel 中显式定义命令属性。源代码生成器会自动为你生成所需的命令属性,从而大大简化了代码。这种方法特别适合于大型项目或者需要频繁创建命令的场景。

标签:CommunityToolKit,Mvvm,ViewModel,RelayCommand,命令,private,WPF,public
From: https://www.cnblogs.com/zeoHere/p/18640770

相关文章

  • WPF DoubleAnimation RepeatBehavior,Duration,SpeedRation,AutoReverse
    //xaml<Windowx:Class="WpfApp114.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.mi......
  • DevExpress WPF中文教程:Grid - 如何实现列和带的固定?
    DevExpressWPF拥有120+个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpressWPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。无论是Office办公软件的衍伸产品,还是以数据为中心......
  • 在 WPF 中将视频中的纯绿色显示为透明
    最近需要制作一个类似桌面宠物的东西,碰到了这样一个问题:受MediaElement支持的带alpha通道的视频格式有限,且后续还要接入相关的深度学习模型动态生成口型,大概率生成不了透明背景。这个该怎么办呢?一个思路是把视频抽帧抠图,然后依次显示透明背景的图片(或者再组合成视频播放)。另外......
  • WPF GeneralTransform3DTo2D TransformToAncestor
    //xaml<Windowx:Class="WpfApp113.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.mi......
  • WPF ModelVisual3D Viewport2DVisual3D
    <Windowx:Class="WpfApp110.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft......
  • WPF Viewport3D ModelVisual3D ModelUIElement3D GeometryModel3D
    //xaml<Windowx:Class="WpfApp109.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.mi......
  • WPF Model3DGroup
    <Windowx:Class="WpfApp108.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft......
  • WPF ViewPort3D ModelVisual3D GeometryModel3D MeshGeometry3D Positions Normals
    <Windowx:Class="WpfApp107.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft......
  • wpf DataGrid 内容绑定动态资源方法
    先讲故事:系统需要区分语言环境,有中文环境与英文环境。然后有一列用户角色列,用户分为管理员(admin)与普通用户(users)。假设管理员用户角色ID为1,普通用户为2.用户角色编码字段名:UseRoleCode。当数据加到到DataGrid 之后,这是切换语言,需要根据当前的语言显示中文或者英文,再不......
  • WPF Viewport3D Model3DGroup GeometryModel3D ModelVisual3D PerspectiveCamera Dir
     Vector3DCollectionPoint3DCollectionPointCollectionInt32CollectionLinearGradientBrushDiffuseMaterial  RotateTransform3DAxisAngleRotation3D usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threadi......