AsyncRelayCommand と AsyncRelayCommand<T>

AsyncRelayCommandAsyncRelayCommand<T> は、RelayCommand によって提供される機能を非同期操作のサポートで拡張する、ICommand の実装です。

Platform API:AsyncRelayCommandAsyncRelayCommand<T>RelayCommandIAsyncRelayCommandIAsyncRelayCommand<T>

そのしくみ

AsyncRelayCommandAsyncRelayCommand<T> の主な機能は次のとおりです。

  • ライブラリに含まれる同期コマンドの機能を、Task を返すデリゲートのサポートで拡張します。
  • 取り消しをサポートするために追加された CancellationToken パラメーターで非同期関数をラップでき、CanBeCanceledIsCancellationRequested プロパティおよび Cancel メソッドを公開します。
  • 保留中の操作の進行状況を監視するために使用できる ExecutionTask プロパティと、操作が完了したタイミングを調べるために使用できる IsRunning を公開します。 これは、読み込みインジケーターなどの UI 要素にコマンドをバインドするのに特に便利です。
  • IAsyncRelayCommandIAsyncRelayCommand<T> インターフェイスを実装します。これは、ViewModel がこれらを使ってコマンドを簡単に公開し、型の間の緊密な結合を減らせることを意味します。 たとえば、これにより、必要に応じて、同じパブリック API サーフェスを公開するカスタム実装でコマンドを簡単に置き換えることができます。

非同期コマンドの使用

RelayCommand サンプルで説明されているのと同じようなシナリオで、ただし非同期操作を実行するコマンドを考えてみましょう。

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

    public IAsyncRelayCommand DownloadTextCommand { get; }

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

関連する UI コードは次のとおりです。

<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 が更新されます。 操作が完了すると、プロパティは UI に反映される通知を生成します。 この場合、タスクの状態とタスクの現在の結果の両方が表示されます。 タスクの結果を表示するには、TaskExtensions.GetResultOrDefault メソッドを使う必要があることに注意してください。これにより、スレッドをブロックすることなく (デッドロックの原因になる可能性があります)、まだ完了していないタスクの結果にアクセスできます。

  • MVVM Toolkit の実際の動作を確認するには、サンプル アプリをご覧ください (複数 UI フレームワークの場合)。
  • 単体テストで、その他の例を確認することもできます。