AsyncRelayCommand y AsyncRelayCommand<T>

Los AsyncRelayCommand y AsyncRelayCommand<T> sonICommand implementaciones que amplían las funcionalidades que ofrece RelayCommand, con compatibilidad con operaciones asincrónicas.

API de la plataforma:AsyncRelayCommand, AsyncRelayCommand<T>, RelayCommand, IAsyncRelayCommand, IAsyncRelayCommand<T>

Cómo funcionan

AsyncRelayCommand y AsyncRelayCommand<T> tienen las siguientes características principales:

  • Amplían las funcionalidades de los comandos sincrónicos incluidos en la biblioteca, con compatibilidad con los delegados que devuelven Task.
  • Pueden encapsular funciones asincrónicas con un parámetro CancellationToken adicional para admitir la cancelación y exponen una CanBeCanceled y IsCancellationRequested propiedades, así como un método Cancel.
  • Exponen una propiedad ExecutionTask que se puede usar para supervisar el progreso de una operación pendiente y un IsRunning que se puede usar para comprobar cuándo se completa una operación. Esto resulta especialmente útil para enlazar un comando a elementos de la interfaz de usuario, como indicadores de carga.
  • Implementan las interfaces IAsyncRelayCommand y IAsyncRelayCommand<T>, lo que significa que el modelo de vista puede exponer fácilmente comandos con estos para reducir el acoplamiento estricto entre tipos. Por ejemplo, esto facilita la sustitución de un comando por una implementación personalizada que expone la misma superficie de API pública, si es necesario.

Trabajar con comandos asincrónicos

Imaginemos un escenario similar al descrito en el ejemplo RelayCommand, pero un comando que ejecuta una operación asincrónica:

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

    public IAsyncRelayCommand DownloadTextCommand { get; }

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

Con el código de interfaz de usuario 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>

Al hacer clic en el Button, se invoca el comando y se actualiza el ExecutionTask. Cuando se completa la operación, la propiedad genera una notificación que se refleja en la interfaz de usuario. En este caso, se muestran el estado de la tarea y el resultado actual de la tarea. Tenga en cuenta que para mostrar el resultado de la tarea, es necesario usar el método TaskExtensions.GetResultOrDefault; esto proporciona acceso al resultado de una tarea que aún no se ha completado sin bloquear el subproceso (y posiblemente provocar un interbloqueo).

Ejemplos

  • Consulte la aplicación de ejemplo (para varios marcos de interfaz de usuario) para ver el kit de herramientas de MVVM en acción.
  • También puede encontrar más ejemplos en las pruebas unitarias.