Share via


AsyncRelayCommand e AsyncRelayCommand<T>

AsyncRelayCommand, AsyncRelayCommand<T> e ICommand são implementações que estendem as funcionalidades oferecidas por RelayCommand, com suporte para operações assíncronas.

APIs de plataforma:AsyncRelayCommand, AsyncRelayCommand<T>, RelayCommand, IAsyncRelayCommand, IAsyncRelayCommand<T>

Como eles funcionam

AsyncRelayCommand e AsyncRelayCommand<T> têm os seguintes recursos principais:

  • Elas estendem as funcionalidades dos comandos síncronos incluídos na biblioteca, com suporte para delegados que retornam Task.
  • Elas podem encapsular funções assíncronas com um parâmetro adicional CancellationToken para dar suporte a cancelamento e expõem propriedades CanBeCanceled e IsCancellationRequested, bem como um método Cancel.
  • Elas expõem uma propriedade ExecutionTask que pode ser usada para monitorar o progresso de uma operação pendente e um IsRunning que pode ser usado para verificar quando uma operação é concluída. Isso é particularmente útil para associar um comando a elementos da interface do usuário, como o carregamento de indicadores.
  • Elas implementam as interfaces IAsyncRelayCommand e IAsyncRelayCommand<T>, o que significa que viewmodel pode facilmente expor comandos usando-as para reduzir o acoplamento apertado entre tipos. Por exemplo, isso facilita a substituição de um comando por uma implementação personalizada expondo a mesma superfície de API pública, se necessário.

Trabalhar com comandos assíncronos

Vamos imaginar um cenário semelhante ao descrito no exemplo RelayCommand, mas um comando executando uma operação assíncrona:

public class MyViewModel : ObservableObject
{
    public MyViewModel()
    {
        DownloadTextCommand = new AsyncRelayCommand(DownloadText);
    }

    public IAsyncRelayCommand DownloadTextCommand { get; }

    private Task<string> DownloadText()
    {
        return WebService.LoadMyTextAsync();
    }
}

Com o código da interface do usuário relacionado:

<Page
    x:Class="MyApp.Views.MyPage"
    xmlns:viewModels="using:MyApp.ViewModels"
    xmlns:converters="using:Microsoft.Toolkit.Uwp.UI.Converters">
    <Page.DataContext>
        <viewModels:MyViewModel x:Name="ViewModel"/>
    </Page.DataContext>
    <Page.Resources>
        <converters:TaskResultConverter x:Key="TaskResultConverter"/>
    </Page.Resources>

    <StackPanel Spacing="8" xml:space="default">
        <TextBlock>
            <Run Text="Task status:"/>
            <Run Text="{x:Bind ViewModel.DownloadTextCommand.ExecutionTask.Status, Mode=OneWay}"/>
            <LineBreak/>
            <Run Text="Result:"/>
            <Run Text="{x:Bind ViewModel.DownloadTextCommand.ExecutionTask, Converter={StaticResource TaskResultConverter}, Mode=OneWay}"/>
        </TextBlock>
        <Button
            Content="Click me!"
            Command="{x:Bind ViewModel.DownloadTextCommand}"/>
        <ProgressRing
            HorizontalAlignment="Left"
            IsActive="{x:Bind ViewModel.DownloadTextCommand.IsRunning, Mode=OneWay}"/>
    </StackPanel>
</Page>

Ao clicar no comando Button, o comando é invocado e ExecutionTask é atualizado. Quando a operação é concluída, a propriedade gera uma notificação que é refletida na interface do usuário. Nesse caso, o status da tarefa e o resultado atual da tarefa são exibidos. Observe que, para mostrar o resultado da tarefa, é necessário usar o método TaskExtensions.GetResultOrDefault – isso fornece acesso ao resultado de uma tarefa que ainda não foi concluída sem bloquear o thread (e possivelmente causar um deadlock).

Exemplos

  • Confira o aplicativo de exemplo (para várias estruturas de interface do usuário) para ver o Kit de Ferramentas MVVM em ação.
  • Você também pode encontrar mais exemplos nos testes de unidade.