AsyncRelayCommand и AsyncRelayCommand<T>

AsyncRelayCommand и AsyncRelayCommand<T> — это реализации ICommand, которые расширяют функциональные возможности, предоставляемые RelayCommand, и поддерживают асинхронные операции.

API платформы:AsyncRelayCommand, AsyncRelayCommand<T>, RelayCommandIAsyncRelayCommandIAsyncRelayCommand<T>

Принцип работы

AsyncRelayCommand и AsyncRelayCommand<T> имеют следующие основные функции:

  • Они расширяют функциональность синхронных команд, включённых в библиотеку, и добавляют поддержку делегатов, возвращающих Task.
  • Они могут оборачивать асинхронные функции, добавляя дополнительный параметр CancellationToken для поддержки отмены операции, а также предоставляют свойства CanBeCanceled и IsCancellationRequested, а также метод Cancel.
  • Они предоставляют свойство ExecutionTask, которое можно использовать для отслеживания хода выполнения незавершённой операции, и элемент IsRunning, который можно использовать, чтобы определить, когда операция завершится. Это особенно полезно для привязки команды к элементам пользовательского интерфейса, таким как индикаторы загрузки.
  • Они реализуют интерфейсы IAsyncRelayCommand и IAsyncRelayCommand<T>, что означает, что модель представления может легко предоставлять команды с их помощью, уменьшая жесткую связанность между типами. Например, это упрощает замену команды пользовательской реализацией, предоставляющей одну и ту же общедоступную область API при необходимости.

Работа с асинхронными командами

Предположим сценарий, аналогичный описанному в RelayCommand примере, но команда, выполняющая асинхронную операцию:

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

    public IAsyncRelayCommand DownloadTextCommand { get; }

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

С соответствующим кодом пользовательского интерфейса:

<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>

После нажатия Buttonкнопки вызывается команда и ExecutionTask обновляется. После завершения операции свойство вызывает уведомление, которое отражается в пользовательском интерфейсе. В этом случае отображаются состояние задачи и текущий результат задачи. Обратите внимание, что для получения результата задачи необходимо использовать метод TaskExtensions.GetResultOrDefault — он предоставляет доступ к результату еще не завершившейся задачи без блокировки потока (что может привести к взаимной блокировке).

Примеры

  • Ознакомьтесь с примером приложения (для нескольких платформ пользовательского интерфейса), чтобы просмотреть набор средств MVVM в действии.
  • Дополнительные примеры можно найти в модульных тестах.