AsyncRelayCommand und AsyncRelayCommand<T>

Bei AsyncRelayCommand und AsyncRelayCommand<T> handelt es sich um ICommand-Implementierungen, die die von RelayCommand angebotenen Funktionalitäten erweitern und asynchrone Operationen unterstützen.

Plattform APIs:AsyncRelayCommand, AsyncRelayCommand<T>, RelayCommand, IAsyncRelayCommand, IAsyncRelayCommand<T>

Funktionsweise

AsyncRelayCommand und AsyncRelayCommand<T> haben die folgenden Hauptfunktionen:

  • Sie erweitern die Funktionalitäten der in der Bibliothek enthaltenen synchronen Befehle um die Unterstützung von Delegaten mit Task-Rückgabe.
  • Sie können asynchrone Funktionen mit einem zusätzlichen CancellationToken-Parameter verpacken, um einen Abbruch zu unterstützen, und sie stellen eine CanBeCanceled- und IsCancellationRequested-Eigenschaft sowie eine Cancel-Methode zur Verfügung.
  • Sie stellen eine ExecutionTask-Eigenschaft zur Verfügung, mit der der Fortschritt einer anstehenden Operation überwacht werden kann, und eine IsRunning-Eigenschaft, mit der überprüft werden kann, wann eine Operation abgeschlossen ist. Dies ist besonders nützlich, um einen Befehl an Benutzeroberflächenelemente wie Ladeanzeigen zu binden.
  • Sie implementieren die IAsyncRelayCommand- und IAsyncRelayCommand<T>-Schnittstellen, was bedeutet, dass das ViewModel Befehle mit Hilfe dieser Schnittstellen leicht offenlegen kann, um die enge Kopplung zwischen den Typen zu verringern. Dies macht es zum Beispiel einfacher, einen Befehl durch eine benutzerdefinierte Implementierung zu ersetzen, die dieselbe öffentliche API-Oberfläche aufweist, falls erforderlich.

Arbeiten mit asynchronen Befehlen

Stellen wir uns ein ähnliches Szenario vor wie das im RelayCommand-Beispiel beschriebene, aber ein Befehl, der eine asynchrone Operation ausführt:

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

    public IAsyncRelayCommand DownloadTextCommand { get; }

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

Mit dem zugehörigen Code für die Benutzeroberfläche:

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

Beim Klicken auf den Befehl Button wird der Befehl aufgerufen und ExecutionTask wird aktualisiert. Wenn der Vorgang abgeschlossen ist, löst die Eigenschaft eine Benachrichtigung aus, die in der Benutzeroberfläche angezeigt wird. In diesem Fall werden sowohl der Status der Aufgabe als auch das aktuelle Ergebnis der Aufgabe angezeigt. Um das Ergebnis der Aufgabe anzuzeigen, muss die TaskExtensions.GetResultOrDefault-Methode verwendet werden. Sie ermöglicht den Zugriff auf das Ergebnis einer Aufgabe, die noch nicht abgeschlossen ist, ohne den Thread zu blockieren (und möglicherweise einen Deadlock zu verursachen).

Beispiele

  • Sehen Sie sich die Beispiel-App (für mehrere Benutzeroberflächen-Frameworks) an, um das MVVM-Toolkit in Aktion zu sehen.
  • Weitere Beispiele finden Sie auch in den Komponententests.