跳转至

异步中继指令 AsyncRelayCommand

异步中继指令更加强大,因为它背后可以是一个异步任务。这个异步任务的状态默认会对按钮控件的可用性进行控制,并且异步任务有办法取消。

我们跳过最朴素的用法,直接展示典型的使用源生成器的例子。

基本用法

partial class MainViewModel : ObservableValidator
{
    [ObservableProperty]
    private string name = "";

    private bool CanSubmit() => !string.IsNullOrEmpty(Name);

    [RelayCommand(CanExecute = nameof(CanSubmit))]
    private async Task SubmitAsync()
    {
        await Task.Delay(1000);
    }
}

Note

后台会为我们生成名为 SubmitCommand 的属性。工具包在生成这个属性时,会自动去掉原始方法名的 Async 结尾。

运行程序后会发现,在点击按钮后,按钮会自动灰掉 1 秒钟。这是因为期间异步任务正在执行,所以按钮会不可用。

取消任务

如果我们想要为这个异步中继指令添加取消功能,除了手动实现,我们还可以借助源生成器。只需要将上例修改为:

[RelayCommand(CanExecute = nameof(CanSubmit), IncludeCancelCommand = true)]
private async Task SubmitAsync(CancellationToken token)
{
    try
    {
        await Task.Delay(2000, token);
    }
    catch (OperationCanceledException)
    {

    }
}

即可。此时后台会为我们额外生成一个名为 SubmitCancelCommand 的中继指令。此时只需要将该中继指令绑定到一个按钮,即可使用。并且运行程序可以发现,这个取消按钮只有在异步任务执行时才会处于可用状态。

此时的 XAML 内容形如:

<StackPanel>
    <TextBox Text="{Binding Name"} />
    <Button Content="Submit" Command="{Binding SubmitCommand}" />
    <Button Content="Cancel" Command="{Binding SubmitCancelCommand}" />
</StackPanel>

Note

如果希望异步任务可以被取消,此时方法必须接受一个 CancellationToken 类型的参数。如果此时还希望该方法能接受一个入参,那么需要将入参作为第一个参数,CancellationToken 作为第二个参数。

异步任务可以多次发起

如果我们希望异步任务可以多次发起,也就是按钮不需要等待上一个任务结束才能继续点击,那么只需要将特性的 AllowConcurrentExecutions 参数设为 true 即可。

评论