487 字
2 分钟
[.NET/WPF] CommunityToolkit.Mvvm 异步指令
我们在开发中, 经常会有这样的需求:
- 点击按钮后, 进行一些耗时的工作
- 工作进行时, 按钮不可再次被点击
- 工作进行时, 会显示进度条, 或者 “加载中” 的动画
RelayCommand
CommunityToolkit.Mvvm 中的 RelayCommand 除了支持最简单的同步方法, 还支持以 Task 作为返回值的异步方法, 当我们为这样的异步方法标记上 RelayCommand 特性时, 它会生成一个对应的异步指令.
- 指令在执行时, 主要逻辑会在后台, 而不是运行在 UI 线程中. 具体可以参考 “异步和异步的线程切换”
- 指令在执行时, CanExecute 会变为 false, 此时使用该 Command 的 Button 或者其他控件, 也会变成 ‘被禁用’ 的状态.
- 如果方法参数中包含一个
CancellationToken, 那么这个任务同样可以被取消. 只需要你方法内部有正确实现 “取消执行” 的逻辑就没问题.
下面是一个例子.
主窗体代码:
<Window x:Class="LearnMvvm.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:LearnMvvm" xmlns:vm="clr-namespace:LearnMvvm.ViewModels" mc:Ignorable="d" Title="MainWindow" Height="450" Width="700"> <Window.DataContext> <vm:MainViewModel/> </Window.DataContext> <Grid> <StackPanel Margin="50"> <Button Command="{Binding DoSomethingCommand}">Do something</Button> <Button Command="{Binding CancelDoSomethingCommand}" Margin="0 5 0 0">Cancel</Button>
<ProgressBar Margin="0 10 0 0" Height="15" Value="{Binding Progress}"/> </StackPanel> </Grid></Window>后台 ViewModel
public partial class MainViewModel : ObservableObject{ [ObservableProperty] private int progress;
[RelayCommand] public async Task DoSomething(CancellationToken token) { for (int i = 0; i <= 100; i++) { if (token.IsCancellationRequested) return;
await Task.Delay(100); Progress = i; } }
[RelayCommand] public void CancelDoSomething() { DoSomethingCommand.Cancel(); }}效果:


在 CommunityToolkit.Mvvm 中, 支持以下样式的 RelayCommand 签名:
void 方法名()无参同步指令void 方法名(类型 参数名)有参同步指令Task 方法名(), 无参, 不支持取消的异步指令Task 方法名(类型 参数名)有参, 不支持取消的异步指令Task 方法名(CancellationToken token)无参, 支持取消的异步指令Task 方法名(类型 参数名, CancellationToken token)有参, 支持取消的异步指令
[.NET/WPF] CommunityToolkit.Mvvm 异步指令
https://slimenull.com/posts/20230818143649/