File tree Expand file tree Collapse file tree 6 files changed +160
-2
lines changed Expand file tree Collapse file tree 6 files changed +160
-2
lines changed Original file line number Diff line number Diff line change 8
8
using System . Threading ;
9
9
using System . Threading . Tasks ;
10
10
using CommunityToolkit . Mvvm . ComponentModel . __Internals ;
11
+ using CommunityToolkit . Mvvm . Input . Internals ;
11
12
12
13
#pragma warning disable CS0618
13
14
@@ -19,7 +20,7 @@ namespace CommunityToolkit.Mvvm.Input;
19
20
/// action, and providing an <see cref="ExecutionTask"/> property that notifies changes when
20
21
/// <see cref="ExecuteAsync"/> is invoked and when the returned <see cref="Task"/> completes.
21
22
/// </summary>
22
- public sealed class AsyncRelayCommand : IAsyncRelayCommand
23
+ public sealed class AsyncRelayCommand : IAsyncRelayCommand , ICancellationAwareCommand
23
24
{
24
25
/// <summary>
25
26
/// The cached <see cref="PropertyChangedEventArgs"/> for <see cref="ExecutionTask"/>.
@@ -252,6 +253,9 @@ static async void MonitorTask(AsyncRelayCommand @this, Task task)
252
253
/// <inheritdoc/>
253
254
public bool IsRunning => ExecutionTask is { IsCompleted : false } ;
254
255
256
+ /// <inheritdoc/>
257
+ bool ICancellationAwareCommand . IsCancellationSupported => this . execute is null ;
258
+
255
259
/// <inheritdoc/>
256
260
public void NotifyCanExecuteChanged ( )
257
261
{
Original file line number Diff line number Diff line change 8
8
using System . Threading ;
9
9
using System . Threading . Tasks ;
10
10
using CommunityToolkit . Mvvm . ComponentModel . __Internals ;
11
+ using CommunityToolkit . Mvvm . Input . Internals ;
11
12
12
13
#pragma warning disable CS0618
13
14
@@ -17,7 +18,7 @@ namespace CommunityToolkit.Mvvm.Input;
17
18
/// A generic command that provides a more specific version of <see cref="AsyncRelayCommand"/>.
18
19
/// </summary>
19
20
/// <typeparam name="T">The type of parameter being passed as input to the callbacks.</typeparam>
20
- public sealed class AsyncRelayCommand < T > : IAsyncRelayCommand < T >
21
+ public sealed class AsyncRelayCommand < T > : IAsyncRelayCommand < T > , ICancellationAwareCommand
21
22
{
22
23
/// <summary>
23
24
/// 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)
234
235
/// <inheritdoc/>
235
236
public bool IsRunning => ExecutionTask is { IsCompleted : false } ;
236
237
238
+ /// <inheritdoc/>
239
+ bool ICancellationAwareCommand . IsCancellationSupported => this . execute is null ;
240
+
237
241
/// <inheritdoc/>
238
242
public void NotifyCanExecuteChanged ( )
239
243
{
Original file line number Diff line number Diff line change
1
+ // Licensed to the .NET Foundation under one or more agreements.
2
+ // The .NET Foundation licenses this file to you under the MIT license.
3
+ // See the LICENSE file in the project root for more information.
4
+
5
+ using System . Windows . Input ;
6
+ using CommunityToolkit . Mvvm . Input . Internals ;
7
+
8
+ namespace CommunityToolkit . Mvvm . Input ;
9
+
10
+ /// <summary>
11
+ /// Extensions for the <see cref="IAsyncRelayCommand"/> type.
12
+ /// </summary>
13
+ public static class IAsyncRelayCommandExtensions
14
+ {
15
+ /// <summary>
16
+ /// Creates an <see cref="ICommand"/> instance that can be used to cancel execution on the input command.
17
+ /// The returned command will also notify when it can be executed based on the state of the wrapped command.
18
+ /// </summary>
19
+ /// <param name="command">The input <see cref="IAsyncRelayCommand"/> instance to create a cancellation command for.</param>
20
+ /// <returns>An <see cref="ICommand"/> instance that can be used to monitor and signal cancellation for <paramref name="command"/>.</returns>
21
+ /// <remarks>The reeturned instance is not guaranteed to be unique across multiple invocations with the same arguments.</remarks>
22
+ /// <exception cref="System.ArgumentNullException">Thrown if <paramref name="command"/> is <see langword="null"/>.</exception>
23
+ public static ICommand CreateCancelCommand ( this IAsyncRelayCommand command )
24
+ {
25
+ ArgumentNullException . ThrowIfNull ( command ) ;
26
+
27
+ // If the command is known not to ever allow cancellation, just reuse the same instance
28
+ if ( command is ICancellationAwareCommand { IsCancellationSupported : false } )
29
+ {
30
+ return DisabledCommand . Instance ;
31
+ }
32
+
33
+ // Create a new cancel command wrapping the input one
34
+ return new CancelCommand ( command ) ;
35
+ }
36
+ }
Original file line number Diff line number Diff line change
1
+ // Licensed to the .NET Foundation under one or more agreements.
2
+ // The .NET Foundation licenses this file to you under the MIT license.
3
+ // See the LICENSE file in the project root for more information.
4
+
5
+ using System ;
6
+ using System . ComponentModel ;
7
+ using System . Windows . Input ;
8
+
9
+ namespace CommunityToolkit . Mvvm . Input . Internals ;
10
+
11
+ /// <summary>
12
+ /// A <see cref="ICommand"/> implementation wrapping <see cref="IAsyncRelayCommand"/> to support cancellation.
13
+ /// </summary>
14
+ internal sealed class CancelCommand : ICommand
15
+ {
16
+ /// <summary>
17
+ /// The wrapped <see cref="IAsyncRelayCommand"/> instance.
18
+ /// </summary>
19
+ private readonly IAsyncRelayCommand command ;
20
+
21
+ /// <summary>
22
+ /// Creates a new <see cref="CancelCommand"/> instance.
23
+ /// </summary>
24
+ /// <param name="command">The <see cref="IAsyncRelayCommand"/> instance to wrap.</param>
25
+ public CancelCommand ( IAsyncRelayCommand command )
26
+ {
27
+ this . command = command ;
28
+
29
+ this . command . PropertyChanged += OnPropertyChanged ;
30
+ }
31
+
32
+ /// <inheritdoc/>
33
+ public event EventHandler ? CanExecuteChanged ;
34
+
35
+ /// <inheritdoc/>
36
+ public bool CanExecute ( object ? parameter )
37
+ {
38
+ return this . command . CanBeCanceled ;
39
+ }
40
+
41
+ /// <inheritdoc/>
42
+ public void Execute ( object ? parameter )
43
+ {
44
+ this . command . Cancel ( ) ;
45
+ }
46
+
47
+ /// <inheritdoc cref="PropertyChangedEventHandler"/>
48
+ private void OnPropertyChanged ( object ? sender , PropertyChangedEventArgs e )
49
+ {
50
+ if ( e . PropertyName is null or nameof ( IAsyncRelayCommand . CanBeCanceled ) )
51
+ {
52
+ CanExecuteChanged ? . Invoke ( this , EventArgs . Empty ) ;
53
+ }
54
+ }
55
+ }
Original file line number Diff line number Diff line change
1
+ // Licensed to the .NET Foundation under one or more agreements.
2
+ // The .NET Foundation licenses this file to you under the MIT license.
3
+ // See the LICENSE file in the project root for more information.
4
+
5
+ using System ;
6
+ using System . Windows . Input ;
7
+
8
+ namespace CommunityToolkit . Mvvm . Input . Internals ;
9
+
10
+ /// <summary>
11
+ /// A reusable <see cref="ICommand"/> instance that is always disabled.
12
+ /// </summary>
13
+ internal sealed class DisabledCommand : ICommand
14
+ {
15
+ /// <inheritdoc/>
16
+ public event EventHandler ? CanExecuteChanged
17
+ {
18
+ add { }
19
+ remove { }
20
+ }
21
+
22
+ /// <summary>
23
+ /// Gets a shared, reusable <see cref="DisabledCommand"/> instance.
24
+ /// </summary>
25
+ /// <remarks>
26
+ /// This instance can safely be used across multiple objects without having
27
+ /// to worry about this static keeping others alive, as the event uses a
28
+ /// custom accessor that just discards items (as the event is known to never
29
+ /// be raised). As such, this instance will never act as root for other objects.
30
+ /// </remarks>
31
+ public static DisabledCommand Instance { get ; } = new ( ) ;
32
+
33
+ /// <inheritdoc/>
34
+ public bool CanExecute ( object ? parameter )
35
+ {
36
+ return false ;
37
+ }
38
+
39
+ /// <inheritdoc/>
40
+ public void Execute ( object ? parameter )
41
+ {
42
+ }
43
+ }
Original file line number Diff line number Diff line change
1
+ // Licensed to the .NET Foundation under one or more agreements.
2
+ // The .NET Foundation licenses this file to you under the MIT license.
3
+ // See the LICENSE file in the project root for more information.
4
+
5
+ namespace CommunityToolkit . Mvvm . Input . Internals ;
6
+
7
+ /// <summary>
8
+ /// An interface for commands that know whether they support cancellation or not.
9
+ /// </summary>
10
+ internal interface ICancellationAwareCommand
11
+ {
12
+ /// <summary>
13
+ /// Gets whether or not the current command supports cancellation.
14
+ /// </summary>
15
+ bool IsCancellationSupported { get ; }
16
+ }
You can’t perform that action at this time.
0 commit comments