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 propriedadesCanBeCanceled
eIsCancellationRequested
, bem como um métodoCancel
. - Elas expõem uma propriedade
ExecutionTask
que pode ser usada para monitorar o progresso de uma operação pendente e umIsRunning
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
eIAsyncRelayCommand<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.