AsyncRelayCommand and AsyncRelayCommand<T>
The AsyncRelayCommand
and AsyncRelayCommand<T>
are ICommand
implementations that extend the functionalities offered by RelayCommand
, with support for asynchronous operations.
Platform APIs:
AsyncRelayCommand
,AsyncRelayCommand<T>
,RelayCommand
,IAsyncRelayCommand
,IAsyncRelayCommand<T>
How they work
AsyncRelayCommand
and AsyncRelayCommand<T>
have the following main features:
- They extend the functionalities of the synchronous commands included in the library, with support for
Task
-returning delegates. - They can wrap asynchronous functions with an additional
CancellationToken
parameter to support cancelation, and they expose aCanBeCanceled
andIsCancellationRequested
properties, as well as aCancel
method. - They expose an
ExecutionTask
property that can be used to monitor the progress of a pending operation, and anIsRunning
that can be used to check when an operation completes. This is particularly useful to bind a command to UI elements such as loading indicators. - They implement the
IAsyncRelayCommand
andIAsyncRelayCommand<T>
interfaces, which means that viewmodel can easily expose commands using these to reduce the tight coupling between types. For instance, this makes it easier to replace a command with a custom implementation exposing the same public API surface, if needed.
Working with asynchronous commands
Let's imagine a scenario similar to the one described in the RelayCommand
sample, but a command executing an asynchronous operation:
public class MyViewModel : ObservableObject
{
public MyViewModel()
{
DownloadTextCommand = new AsyncRelayCommand(DownloadText);
}
public IAsyncRelayCommand DownloadTextCommand { get; }
private Task<string> DownloadText()
{
return WebService.LoadMyTextAsync();
}
}
With the related UI code:
<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>
Upon clicking the Button
, the command is invoked, and the ExecutionTask
updated. When the operation completes, the property raises a notification which is reflected in the UI. In this case, both the task status and the current result of the task are displayed. Note that to show the result of the task, it is necessary to use the TaskExtensions.GetResultOrDefault
method - this provides access to the result of a task that has not yet completed without blocking the thread (and possibly causing a deadlock).
Examples
- Check out the sample app (for multiple UI frameworks) to see the MVVM Toolkit in action.
- You can also find more examples in the unit tests.
MVVM Toolkit