Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
ObservableTaskCommand.cs
1using System;
2using System.ComponentModel;
3using System.Threading.Tasks;
4using CommunityToolkit.Mvvm.Input;
5
7{
8 [Flags]
9 public enum ObservableTaskCommandOptions
10 {
11 None = 0,
12 AllowConcurrentRestart = 1 << 0,
13 }
14
15 public class ObservableTaskCommand<TProgress> : IAsyncRelayCommand
16 {
17 private readonly Func<TaskContext<TProgress>, Task> taskFactory;
18 private readonly Func<bool>? canExecute;
19 private readonly ObservableTaskCommandOptions options;
20
21 public ObservableTask<TProgress> Notifier { get; }
22
23 // Constructor without canExecute (defaults to always executable and no options)
25 Func<TaskContext<TProgress>, Task> taskFactory)
26 : this(taskFactory, null, ObservableTaskCommandOptions.None)
27 {
28 }
29
30 // Constructor with optional canExecute and options
32 Func<TaskContext<TProgress>, Task> taskFactory,
33 Func<bool>? canExecute,
34 ObservableTaskCommandOptions options = ObservableTaskCommandOptions.None)
35 {
36 this.taskFactory = taskFactory ?? throw new ArgumentNullException(nameof(taskFactory));
37 this.canExecute = canExecute;
38 this.options = options;
39 this.Notifier = new ObservableTask<TProgress>();
40 // Forward property changes from the notifier to this command.
41 this.Notifier.PropertyChanged += (s, e) => this.PropertyChanged?.Invoke(this, e);
42 }
43
47 public async Task ExecuteAsync()
48 {
49 if (!this.CanExecute(null))
50 return;
51
52 this.NotifyCanExecuteChanged();
53
54 // Start the task via the notifier.
55 this.Notifier.Load(ctx => this.taskFactory(ctx), this);
56 Task? Task = this.Notifier.CurrentTask;
57 if (Task is not null)
58 {
59 // When the task completes, raise CanExecuteChanged (on the UI thread).
60 await Task.ContinueWith(
61 _ => this.NotifyCanExecuteChanged(),
62 TaskScheduler.FromCurrentSynchronizationContext());
63 this.NotifyCanExecuteChanged();
64 }
65 }
66
70 public Task ExecuteAsync(object? parameter) => this.ExecuteAsync();
71
75 public bool CanExecute(object? parameter)
76 {
77 bool BaseCanExecute = this.canExecute?.Invoke() ?? true;
78 if (!BaseCanExecute)
79 return false;
80
81 // If concurrent restarts are not allowed, return false if a task is running.
82 if ((this.options & ObservableTaskCommandOptions.AllowConcurrentRestart) == 0)
83 {
84 if (this.Notifier.IsRunning)
85 return false;
86 }
87 return true;
88 }
89
90 public event EventHandler? CanExecuteChanged;
91 public void NotifyCanExecuteChanged() => this.CanExecuteChanged?.Invoke(this, EventArgs.Empty);
92
96 public void Execute(object? parameter) => _ = this.ExecuteAsync();
97
98 public event PropertyChangedEventHandler? PropertyChanged;
99
103 public void Cancel() => this.Notifier.Cancel();
104
108 public Task? ExecutionTask => this.Notifier.CurrentTask;
109
113 public bool CanBeCanceled =>
114 this.Notifier.CancellationTokenSource is not null &&
115 this.Notifier.CurrentTask is not null &&
116 !this.Notifier.CurrentTask.IsCompleted;
117
121 public bool IsCancellationRequested => this.Notifier.CancellationTokenSource?.IsCancellationRequested ?? false;
122
126 public bool IsRunning => this.Notifier.CurrentTask is { IsCompleted: false };
127 }
128}
bool IsCancellationRequested
Indicates whether cancellation has been requested.
bool IsRunning
Indicates whether the command is currently running.
void Cancel()
Cancels the running task.
bool CanExecute(object? parameter)
Checks whether the command can execute.
async Task ExecuteAsync()
Executes the task by starting it through the notifier.
Task ExecuteAsync(object? parameter)
IAsyncRelayCommand overload.
void Execute(object? parameter)
ICommand implementation.
bool CanBeCanceled
Indicates whether the command can be canceled.
Task? ExecutionTask
Exposes the currently executing task.
Provides a data-binding friendly mechanism to manage and report the status of asynchronous operations...
Task? CurrentTask
The current task being processed.
void Load(Func< TaskContext< TProgress >, Task > task, params IRelayCommand[] notifyCommands)
Loads (configures) and immediately starts the task (back-compat convenience).
Definition: ImplTypes.g.cs:58
class TaskContext< TProgress >(bool IsRefreshing, CancellationToken CancellationToken, IProgress< TProgress > Progress)
Represents the context for an asynchronous task execution.
Definition: TaskContext.cs:9