mirror of
https://github.com/chylex/.NET-Community-Toolkit.git
synced 2025-08-08 20:40:36 +02:00
Add IAsyncRelayCommandExtensions.CreateCancelCommand
This commit is contained in:
parent
3fc61fe03d
commit
8ae1006b4d
CommunityToolkit.Mvvm/Input
@ -8,6 +8,7 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.ComponentModel.__Internals;
|
||||
using CommunityToolkit.Mvvm.Input.Internals;
|
||||
|
||||
#pragma warning disable CS0618
|
||||
|
||||
@ -19,7 +20,7 @@ namespace CommunityToolkit.Mvvm.Input;
|
||||
/// action, and providing an <see cref="ExecutionTask"/> property that notifies changes when
|
||||
/// <see cref="ExecuteAsync"/> is invoked and when the returned <see cref="Task"/> completes.
|
||||
/// </summary>
|
||||
public sealed class AsyncRelayCommand : IAsyncRelayCommand
|
||||
public sealed class AsyncRelayCommand : IAsyncRelayCommand, ICancellationAwareCommand
|
||||
{
|
||||
/// <summary>
|
||||
/// The cached <see cref="PropertyChangedEventArgs"/> for <see cref="ExecutionTask"/>.
|
||||
@ -252,6 +253,9 @@ static async void MonitorTask(AsyncRelayCommand @this, Task task)
|
||||
/// <inheritdoc/>
|
||||
public bool IsRunning => ExecutionTask is { IsCompleted: false };
|
||||
|
||||
/// <inheritdoc/>
|
||||
bool ICancellationAwareCommand.IsCancellationSupported => this.execute is null;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void NotifyCanExecuteChanged()
|
||||
{
|
||||
|
@ -8,6 +8,7 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.ComponentModel.__Internals;
|
||||
using CommunityToolkit.Mvvm.Input.Internals;
|
||||
|
||||
#pragma warning disable CS0618
|
||||
|
||||
@ -17,7 +18,7 @@ namespace CommunityToolkit.Mvvm.Input;
|
||||
/// A generic command that provides a more specific version of <see cref="AsyncRelayCommand"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of parameter being passed as input to the callbacks.</typeparam>
|
||||
public sealed class AsyncRelayCommand<T> : IAsyncRelayCommand<T>
|
||||
public sealed class AsyncRelayCommand<T> : IAsyncRelayCommand<T>, ICancellationAwareCommand
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="Func{TResult}"/> to invoke when <see cref="Execute(T)"/> is used.
|
||||
@ -234,6 +235,9 @@ static async void MonitorTask(AsyncRelayCommand<T> @this, Task task)
|
||||
/// <inheritdoc/>
|
||||
public bool IsRunning => ExecutionTask is { IsCompleted: false };
|
||||
|
||||
/// <inheritdoc/>
|
||||
bool ICancellationAwareCommand.IsCancellationSupported => this.execute is null;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void NotifyCanExecuteChanged()
|
||||
{
|
||||
|
36
CommunityToolkit.Mvvm/Input/IAsyncRelayCommandExtensions.cs
Normal file
36
CommunityToolkit.Mvvm/Input/IAsyncRelayCommandExtensions.cs
Normal file
@ -0,0 +1,36 @@
|
||||
// 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.Windows.Input;
|
||||
using CommunityToolkit.Mvvm.Input.Internals;
|
||||
|
||||
namespace CommunityToolkit.Mvvm.Input;
|
||||
|
||||
/// <summary>
|
||||
/// Extensions for the <see cref="IAsyncRelayCommand"/> type.
|
||||
/// </summary>
|
||||
public static class IAsyncRelayCommandExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an <see cref="ICommand"/> instance that can be used to cancel execution on the input command.
|
||||
/// The returned command will also notify when it can be executed based on the state of the wrapped command.
|
||||
/// </summary>
|
||||
/// <param name="command">The input <see cref="IAsyncRelayCommand"/> instance to create a cancellation command for.</param>
|
||||
/// <returns>An <see cref="ICommand"/> instance that can be used to monitor and signal cancellation for <paramref name="command"/>.</returns>
|
||||
/// <remarks>The reeturned instance is not guaranteed to be unique across multiple invocations with the same arguments.</remarks>
|
||||
/// <exception cref="System.ArgumentNullException">Thrown if <paramref name="command"/> is <see langword="null"/>.</exception>
|
||||
public static ICommand CreateCancelCommand(this IAsyncRelayCommand command)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
|
||||
// If the command is known not to ever allow cancellation, just reuse the same instance
|
||||
if (command is ICancellationAwareCommand { IsCancellationSupported: false })
|
||||
{
|
||||
return DisabledCommand.Instance;
|
||||
}
|
||||
|
||||
// Create a new cancel command wrapping the input one
|
||||
return new CancelCommand(command);
|
||||
}
|
||||
}
|
55
CommunityToolkit.Mvvm/Input/Internals/CancelCommand.cs
Normal file
55
CommunityToolkit.Mvvm/Input/Internals/CancelCommand.cs
Normal file
@ -0,0 +1,55 @@
|
||||
// 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.ComponentModel;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace CommunityToolkit.Mvvm.Input.Internals;
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="ICommand"/> implementation wrapping <see cref="IAsyncRelayCommand"/> to support cancellation.
|
||||
/// </summary>
|
||||
internal sealed class CancelCommand : ICommand
|
||||
{
|
||||
/// <summary>
|
||||
/// The wrapped <see cref="IAsyncRelayCommand"/> instance.
|
||||
/// </summary>
|
||||
private readonly IAsyncRelayCommand command;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="CancelCommand"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="command">The <see cref="IAsyncRelayCommand"/> instance to wrap.</param>
|
||||
public CancelCommand(IAsyncRelayCommand command)
|
||||
{
|
||||
this.command = command;
|
||||
|
||||
this.command.PropertyChanged += OnPropertyChanged;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler? CanExecuteChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool CanExecute(object? parameter)
|
||||
{
|
||||
return this.command.CanBeCanceled;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Execute(object? parameter)
|
||||
{
|
||||
this.command.Cancel();
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="PropertyChangedEventHandler"/>
|
||||
private void OnPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName is null or nameof(IAsyncRelayCommand.CanBeCanceled))
|
||||
{
|
||||
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
43
CommunityToolkit.Mvvm/Input/Internals/DisabledCommand.cs
Normal file
43
CommunityToolkit.Mvvm/Input/Internals/DisabledCommand.cs
Normal file
@ -0,0 +1,43 @@
|
||||
// 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.Windows.Input;
|
||||
|
||||
namespace CommunityToolkit.Mvvm.Input.Internals;
|
||||
|
||||
/// <summary>
|
||||
/// A reusable <see cref="ICommand"/> instance that is always disabled.
|
||||
/// </summary>
|
||||
internal sealed class DisabledCommand : ICommand
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler? CanExecuteChanged
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a shared, reusable <see cref="DisabledCommand"/> instance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This instance can safely be used across multiple objects without having
|
||||
/// to worry about this static keeping others alive, as the event uses a
|
||||
/// custom accessor that just discards items (as the event is known to never
|
||||
/// be raised). As such, this instance will never act as root for other objects.
|
||||
/// </remarks>
|
||||
public static DisabledCommand Instance { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool CanExecute(object? parameter)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Execute(object? parameter)
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
// 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.
|
||||
|
||||
namespace CommunityToolkit.Mvvm.Input.Internals;
|
||||
|
||||
/// <summary>
|
||||
/// An interface for commands that know whether they support cancellation or not.
|
||||
/// </summary>
|
||||
internal interface ICancellationAwareCommand
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets whether or not the current command supports cancellation.
|
||||
/// </summary>
|
||||
bool IsCancellationSupported { get; }
|
||||
}
|
Loading…
Reference in New Issue
Block a user