// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Runtime.CompilerServices; using System.Threading.Tasks; using Microsoft.Toolkit.Mvvm.ComponentModel; namespace Microsoft.Toolkit.Mvvm.Input { /// /// A command that mirrors the functionality of , with the addition of /// accepting a returning a as the execute /// action, and providing an property that notifies changes when /// is invoked and when the returned completes. /// public sealed class AsyncRelayCommand : ObservableObject, IAsyncRelayCommand { /// /// The to invoke when is used. /// private readonly Func execute; /// /// The optional action to invoke when is used. /// private readonly Func? canExecute; /// public event EventHandler? CanExecuteChanged; /// /// Initializes a new instance of the class that can always execute. /// /// The execution logic. public AsyncRelayCommand(Func execute) { this.execute = execute; } /// /// Initializes a new instance of the class that can always execute. /// /// The execution logic. /// The execution status logic. public AsyncRelayCommand(Func execute, Func canExecute) { this.execute = execute; this.canExecute = canExecute; } private Task? executionTask; /// public Task? ExecutionTask { get => this.executionTask; private set => SetAndNotifyOnCompletion(ref executionTask, () => executionTask, value); } /// public void NotifyCanExecuteChanged() { CanExecuteChanged?.Invoke(this, EventArgs.Empty); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool CanExecute(object parameter) { return this.canExecute?.Invoke() != false; } /// public void Execute(object parameter) { ExecuteAsync(parameter); } /// public Task ExecuteAsync(object parameter) { if (CanExecute(parameter)) { return ExecutionTask = this.execute(); } return Task.CompletedTask; } } }