Skip to content

Commit 8a15d56

Browse files
committed
feat: async commands
changes: - the `IAsyncRelayCommand` interface added - the `IAsyncRelayCommand<T>` interface added - the `AsyncRelayCommand` implementation added - the `AsyncRelayCommand<T>` implementation added closes #85
1 parent 5142c9d commit 8a15d56

File tree

2 files changed

+169
-0
lines changed

2 files changed

+169
-0
lines changed
+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
using BB84.Notifications.Interfaces;
2+
3+
namespace BB84.Notifications;
4+
5+
/// <summary>
6+
/// The async relay command class.
7+
/// </summary>
8+
/// <param name="execute">The task to execute.</param>
9+
/// <param name="canExecute">The condition to execute.</param>
10+
public sealed class AsyncRelayCommand(Func<Task> execute, Func<bool>? canExecute) : IAsyncRelayCommand
11+
{
12+
private bool _isExecuting;
13+
14+
/// <summary>
15+
/// Initializes a new instance of the <see cref="AsyncRelayCommand"/> class that can always execute.
16+
/// </summary>
17+
/// <param name="execute">The task to execute.</param>
18+
public AsyncRelayCommand(Func<Task> execute) : this(execute, null)
19+
{ }
20+
21+
/// <inheritdoc/>
22+
public event EventHandler? CanExecuteChanged;
23+
24+
/// <inheritdoc/>
25+
public bool CanExecute()
26+
=> !_isExecuting && (canExecute?.Invoke() ?? true);
27+
28+
/// <inheritdoc/>
29+
public async Task ExecuteAsync()
30+
{
31+
if (CanExecute())
32+
{
33+
try
34+
{
35+
_isExecuting = true;
36+
await execute();
37+
}
38+
finally
39+
{
40+
_isExecuting = false;
41+
}
42+
}
43+
44+
RaiseCanExecuteChanged();
45+
}
46+
47+
/// <inheritdoc/>
48+
public bool CanExecute(object? parameter)
49+
=> CanExecute();
50+
51+
/// <inheritdoc/>
52+
public void Execute(object? parameter)
53+
=> ExecuteAsync().Wait();
54+
55+
/// <inheritdoc/>
56+
public void RaiseCanExecuteChanged()
57+
=> CanExecuteChanged?.Invoke(this, EventArgs.Empty);
58+
}
59+
60+
/// <summary>
61+
/// The async relay command class.
62+
/// </summary>
63+
/// <remarks>
64+
/// For all commands that need a parameter.
65+
/// </remarks>
66+
/// <typeparam name="T">The generic type to work with.</typeparam>
67+
/// <param name="execute">The task to execute.</param>
68+
/// <param name="canExecute">The condition to execute.</param>
69+
public sealed class AsyncRelayCommand<T>(Func<T, Task> execute, Func<T, bool>? canExecute) : IAsyncRelayCommand<T>
70+
{
71+
private bool _isExecuting;
72+
73+
/// <summary>
74+
/// Initializes a new instance of <see cref="AsyncRelayCommand{T}"/> class that can always execute.
75+
/// </summary>
76+
/// <param name="execute">The task to execute.</param>
77+
public AsyncRelayCommand(Func<T, Task> execute) : this(execute, null)
78+
{ }
79+
80+
/// <inheritdoc/>
81+
public event EventHandler? CanExecuteChanged;
82+
83+
/// <inheritdoc/>
84+
public bool CanExecute(T parameter)
85+
=> !_isExecuting && (canExecute?.Invoke(parameter) ?? true);
86+
87+
/// <inheritdoc/>
88+
public bool CanExecute(object? parameter)
89+
=> CanExecute((T)parameter!);
90+
91+
/// <inheritdoc/>
92+
public void Execute(object? parameter)
93+
=> ExecuteAsync((T)parameter!).Wait();
94+
95+
/// <inheritdoc/>
96+
public async Task ExecuteAsync(T parameter)
97+
{
98+
if (CanExecute(parameter))
99+
{
100+
try
101+
{
102+
_isExecuting = true;
103+
await execute(parameter);
104+
}
105+
finally
106+
{
107+
_isExecuting = false;
108+
}
109+
}
110+
111+
RaiseCanExecuteChanged();
112+
}
113+
114+
/// <inheritdoc/>
115+
public void RaiseCanExecuteChanged()
116+
=> CanExecuteChanged?.Invoke(this, EventArgs.Empty);
117+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using System.Windows.Input;
2+
3+
namespace BB84.Notifications.Interfaces;
4+
5+
/// <summary>
6+
/// The async relay command interface.
7+
/// </summary>
8+
public interface IAsyncRelayCommand : ICommand
9+
{
10+
/// <summary>
11+
/// Defines the method to be called when the command is invoked.
12+
/// </summary>
13+
/// <returns><see cref="Task"/></returns>
14+
Task ExecuteAsync();
15+
16+
/// <summary>
17+
/// Defines the method that determines whether the command can execute in its current state.
18+
/// </summary>
19+
/// <returns>True if this command can be executed, otherwise false.</returns>
20+
bool CanExecute();
21+
22+
/// <summary>
23+
/// Notifies that the <see cref="ICommand.CanExecuteChanged"/> property has changed.
24+
/// </summary>
25+
void RaiseCanExecuteChanged();
26+
}
27+
28+
/// <summary>
29+
/// The async relay command interface.
30+
/// </summary>
31+
/// <typeparam name="T">The generic type to wor with.</typeparam>
32+
public interface IAsyncRelayCommand<T> : ICommand
33+
{
34+
/// <summary>
35+
/// Defines the method to be called when the command is invoked.
36+
/// </summary>
37+
/// <param name="parameter">The data used by the command.</param>
38+
/// <returns><see cref="Task"/></returns>
39+
Task ExecuteAsync(T parameter);
40+
41+
/// <summary>
42+
/// Defines the method that determines whether the command can execute in its current state.
43+
/// </summary>
44+
/// <param name="parameter">The data used by the command.</param>
45+
/// <returns>True if this command can be executed, otherwise false.</returns>
46+
bool CanExecute(T parameter);
47+
48+
/// <summary>
49+
/// Notifies that the <see cref="ICommand.CanExecuteChanged"/> property has changed.
50+
/// </summary>
51+
void RaiseCanExecuteChanged();
52+
}

0 commit comments

Comments
 (0)