CommunityToolkit.Mvvm的使用-RelayCommand 特性

1.工作原理

[RelayCommand]
private void GreetUser()
{
    Console.WriteLine("Hello!");
}

生成器将使用方法名称并在末尾追加“Command”,并且去除“On”前缀(如果存在)。 此外,对于异步方法,“Async”后缀也会在追加“Command”之前去除。

2.命令参数

[RelayCommand]
private void GreetUser(User user)
{
    Console.WriteLine($"Hello {user.Name}!");
}

该 [RelayCommand] 特性支持使用参数为方法创建命令。 在这种情况下,它会自动将生成的命令更改为 IRelayCommand<T>,从而接受相同类型的参数

界面代码绑定示例

<!-- 1. 直接传递已知的 User 对象 -->
<Button Content="Greet Admin" 
        Command="{Binding GreetUserCommand}"
        CommandParameter="{Binding AdminUser}" />
<!-- 假设 ViewModel 中有一个 AdminUser 属性 -->

<!-- 2. 从列表中传递选中的 User 项 -->
<ListBox x:Name="UsersList" 
         ItemsSource="{Binding AllUsers}" 
         DisplayMemberPath="Name"/>

<Button Content="Greet Selected User"
        Command="{Binding GreetUserCommand}"
        CommandParameter="{Binding SelectedItem, ElementName=UsersList}" />

<!-- 3. 从数据模板中传递当前项 -->
<ItemsControl ItemsSource="{Binding AllUsers}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Name}" />
                <Button Content="Greet"
                        Command="{Binding DataContext.GreetUserCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
                        CommandParameter="{Binding}" />
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

3.异步命令



[RelayCommand]
private async Task GreetUserAsync()
{
    User user = await userService.GetCurrentUserAsync();

    Console.WriteLine($"Hello {user.Name}!");
}

绑定方式和一般的命令一样

使用场景:

  • 避免 UI 线程阻塞(网络请求通常耗时数百毫秒到几秒)。
  • 自动管理命令状态(执行中禁用按钮,防止重复提交)。

4.启用和禁用命令

执行命令时判断一下,是否可行

[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(GreetUserCommand))]
private User? selectedUser;
[RelayCommand(CanExecute = nameof(CanGreetUser))]
private void GreetUser(User? user)
{
    Console.WriteLine($"Hello {user!.Name}!");
}

private bool CanGreetUser(User? user)
{
    return user is not null;
}

 

<!-- Note: this example uses traditional XAML binding syntax -->
<Button
    Content="Greet user"
    Command="{Binding GreetUserCommand}"
    CommandParameter="{Binding SelectedUser}"/>

这个示例代码判断是否为null,如果null则按钮禁用

 5.处理并发执行

[RelayCommand] 特性的 AllowConcurrentExecutions 属性用于用于控制是否允许允许命令的并发执行。默认情况下,异步命令不允许并发执行(即前一个命令未完成时,新的命令调用会被忽略),通过设置 AllowConcurrentExecutions = true 可以允许并发执行。实际应用场景:

不允许并发:提交表单、保存数据等操作(避免重复提交) 允许并发:独立的查询操作、批量处理不同数据等(可以同时执行多个实例)

6.处理异步异常

  1. )异常传播机制:
    • 默认情况下(FlowExceptionsToTaskScheduler = false),异步命令中的异常会被内部捕获,不会向上传播
    • 当设置为 true 时,异常会被传递到任务调度器(通常是 UI 线程),可以通过全局异常处理捕获
  2. 使用场景:
    • 集中式异常处理:当应用有全局异常处理机制时(如示例中的 DispatcherUnhandledException),方便统一处理所有命令异常
    • 减少重复代码:无需在每个命令中编写相同的 try-catch 逻辑
    • 致命错误处理:对于需要终止操作或重启应用的严重错误,适合传播到上层处理
  3. 与常规异常处理的区别:常规方式:在命令内部用 try-catch 处理特定异常FlowExceptionsToTaskScheduler:将异常委托给全局处理机制,适合通用异常处理
  4. [RelayCommand(FlowExceptionsToTaskScheduler = true)]
    private async Task GreetUserAsync(CancellationToken token)
    {
        User user = await userService.GetCurrentUserAsync(token);
    
        Console.WriteLine($"Hello {user.Name}!");
    }

     

7.取消异步操作命令

[RelayCommand(IncludeCancelCommand = true)]
private async Task DoWorkAsync(CancellationToken token)
{
    // Do some long running work...
}

使用场景:进度条中断

8.自定义特性

posted @ 2025-08-18 11:38  灰色淡季  阅读(319)  评论(0)    收藏  举报