diff --git a/29WxOrderWpf/Common/AsyncDelegateCommand.cs b/29WxOrderWpf/Common/AsyncDelegateCommand.cs
new file mode 100644
index 0000000..993112b
--- /dev/null
+++ b/29WxOrderWpf/Common/AsyncDelegateCommand.cs
@@ -0,0 +1,245 @@
+using System.Linq.Expressions;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Input;
+using System.Reflection.Emit;
+using System.Resources;
+using _29WxOrderWpf.Commands;
+
+
+namespace _29WxOrderWpf.Common
+{
+
+ ///
+ /// Provides an implementation of the
+ ///
+ public class AsyncDelegateCommand : DelegateCommandBase, IAsyncCommand
+ {
+ private bool _enableParallelExecution = false;
+ private bool _isExecuting = false;
+ private readonly Func _executeMethod;
+ private Func _canExecuteMethod;
+ private Func _getCancellationToken = () => CancellationToken.None;
+
+ ///
+ /// Creates a new instance of with the to invoke on execution.
+ ///
+ /// The to invoke when is called.
+ public AsyncDelegateCommand(Func executeMethod)
+#if NET6_0_OR_GREATER
+ : this (c => executeMethod().WaitAsync(c), () => true)
+#else
+ : this(c => executeMethod(), () => true)
+#endif
+ {
+
+ }
+
+ ///
+ /// Creates a new instance of with the to invoke on execution.
+ ///
+ /// The to invoke when is called.
+ public AsyncDelegateCommand(Func executeMethod)
+ : this(executeMethod, () => true)
+ {
+
+ }
+
+ ///
+ /// Creates a new instance of with the to invoke on execution
+ /// and a to query for determining if the command can execute.
+ ///
+ /// The to invoke when is called.
+ /// The delegate to invoke when is called
+ public AsyncDelegateCommand(Func executeMethod, Func canExecuteMethod)
+#if NET6_0_OR_GREATER
+ : this(c => executeMethod().WaitAsync(c), canExecuteMethod)
+#else
+ : this(c => executeMethod(), canExecuteMethod)
+#endif
+ {
+ }
+
+ ///
+ /// Creates a new instance of with the to invoke on execution
+ /// and a to query for determining if the command can execute.
+ ///
+ /// The to invoke when is called.
+ /// The delegate to invoke when is called
+ public AsyncDelegateCommand(Func executeMethod, Func canExecuteMethod)
+ : base()
+ {
+ if (executeMethod == null || canExecuteMethod == null)
+ throw new ArgumentNullException(nameof(executeMethod), "Neither the executeMethod nor the canExecuteMethod delegates can be null");
+
+ _executeMethod = executeMethod;
+ _canExecuteMethod = canExecuteMethod;
+ }
+
+ ///
+ /// Gets the current state of the AsyncDelegateCommand
+ ///
+ public bool IsExecuting
+ {
+ get => _isExecuting;
+ private set
+ {
+ _isExecuting = value;
+ OnCanExecuteChanged();
+ }
+ }
+
+ ///
+ /// Executes the command.
+ ///
+ public async Task Execute(CancellationToken? cancellationToken = null)
+ {
+ var token = cancellationToken ?? _getCancellationToken();
+ try
+ {
+ if (!_enableParallelExecution && IsExecuting)
+ return;
+
+ IsExecuting = true;
+ await _executeMethod(token)
+ .ConfigureAwait(false);
+ }
+ catch
+ {
+ throw;
+
+ }
+ finally
+ {
+ IsExecuting = false;
+ }
+ }
+
+ ///
+ /// Determines if the command can be executed.
+ ///
+ /// Returns if the command can execute,otherwise returns .
+ public bool CanExecute()
+ {
+ try
+ {
+ if (!_enableParallelExecution && IsExecuting)
+ return false;
+
+ return _canExecuteMethod?.Invoke() ?? true;
+ }
+ catch (Exception ex)
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// Handle the internal invocation of
+ ///
+ /// Command Parameter
+ protected override async void Execute(object parameter)
+ {
+ // We don't want to wrap this in a try/catch because we already handle
+ // or mean to rethrow the exception in the call with the CancellationToken.
+ var cancellationToken = _getCancellationToken();
+ await Execute(cancellationToken)
+ .ConfigureAwait(false);
+ }
+
+ ///
+ /// Handle the internal invocation of
+ ///
+ ///
+ /// if the Command Can Execute, otherwise
+ protected override bool CanExecute(object parameter)
+ {
+ return CanExecute();
+ }
+
+ ///
+ /// Enables Parallel Execution of Async Tasks
+ ///
+ /// The current instance of .
+ public AsyncDelegateCommand EnableParallelExecution()
+ {
+ _enableParallelExecution = true;
+ return this;
+ }
+
+ ///
+ /// Sets the based on the specified timeout.
+ ///
+ /// A specified timeout.
+ /// The current instance of .
+ public AsyncDelegateCommand CancelAfter(TimeSpan timeout) =>
+ CancellationTokenSourceFactory(() => new CancellationTokenSource(timeout).Token);
+
+ ///
+ /// Provides a delegate callback to provide a default CancellationToken when the Command is invoked.
+ ///
+ /// The default Factory.
+ /// The current instance of .
+ public AsyncDelegateCommand CancellationTokenSourceFactory(Func factory)
+ {
+ _getCancellationToken = factory;
+ return this;
+ }
+
+ ///
+ /// Observes a property that implements INotifyPropertyChanged, and automatically calls DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications.
+ ///
+ /// The object type containing the property specified in the expression.
+ /// The property expression. Example: ObservesProperty(() => PropertyName).
+ /// The current instance of .
+ public AsyncDelegateCommand ObservesProperty(Expression> propertyExpression)
+ {
+ ObservesPropertyInternal(propertyExpression);
+ return this;
+ }
+
+ ///
+ /// Observes a property that is used to determine if this command can execute, and if it implements INotifyPropertyChanged it will automatically call DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications.
+ ///
+ /// The property expression. Example: ObservesCanExecute(() => PropertyName).
+ /// The current instance of .
+ public AsyncDelegateCommand ObservesCanExecute(Expression> canExecuteExpression)
+ {
+ _canExecuteMethod = canExecuteExpression.Compile();
+ ObservesPropertyInternal(canExecuteExpression);
+ return this;
+ }
+
+ ///
+ /// Provides the ability to connect a delegate to catch exceptions encountered by CanExecute or the Execute methods of the DelegateCommand
+ ///
+ /// TThe callback when a specific exception is encountered
+ /// The current instance of .
+ public AsyncDelegateCommand Catch(Action @catch)
+ where TException : Exception
+ {
+ return this;
+ }
+
+ ///
+ /// Provides the ability to connect a delegate to catch exceptions encountered by CanExecute or the Execute methods of the DelegateCommand
+ ///
+ /// The generic / default callback when an exception is encountered
+ /// The current instance of .
+ public AsyncDelegateCommand Catch(Action @catch)
+ {
+ return this;
+ }
+
+ Task IAsyncCommand.ExecuteAsync(object parameter)
+ {
+ return Execute(_getCancellationToken());
+ }
+
+ Task IAsyncCommand.ExecuteAsync(object parameter, CancellationToken cancellationToken)
+ {
+ return Execute(cancellationToken);
+ }
+ }
+}
\ No newline at end of file
diff --git a/29WxOrderWpf/Common/AsyncDelegateCommand{T}.cs b/29WxOrderWpf/Common/AsyncDelegateCommand{T}.cs
new file mode 100644
index 0000000..6595c82
--- /dev/null
+++ b/29WxOrderWpf/Common/AsyncDelegateCommand{T}.cs
@@ -0,0 +1,285 @@
+using System.Linq.Expressions;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Input;
+using System.Reflection.Emit;
+using System.Resources;
+using _29WxOrderWpf.Commands;
+
+namespace _29WxOrderWpf.Common
+{
+ ///
+ /// Provides an implementation of the with a generic parameter type.
+ ///
+ ///
+ public class AsyncDelegateCommand : DelegateCommandBase, IAsyncCommand
+ {
+ private bool _enableParallelExecution = false;
+ private bool _isExecuting = false;
+ private readonly Func _executeMethod;
+ private Func _canExecuteMethod;
+ private Func _getCancellationToken = () => CancellationToken.None;
+
+ ///
+ /// Creates a new instance of with the to invoke on execution.
+ ///
+ /// The to invoke when is called.
+ public AsyncDelegateCommand(Func executeMethod)
+#if NET6_0_OR_GREATER
+ : this((p,t) => executeMethod(p).WaitAsync(t), _ => true)
+#else
+ : this((p, t) => executeMethod(p), _ => true)
+#endif
+ {
+
+ }
+
+ ///
+ /// Creates a new instance of with the to invoke on execution.
+ ///
+ /// The to invoke when is called.
+ public AsyncDelegateCommand(Func executeMethod)
+ : this(executeMethod, _ => true)
+ {
+
+ }
+
+ ///
+ /// Creates a new instance of with the to invoke on execution
+ /// and a to query for determining if the command can execute.
+ ///
+ /// The to invoke when is called.
+ /// The delegate to invoke when is called
+ public AsyncDelegateCommand(Func executeMethod, Func canExecuteMethod)
+#if NET6_0_OR_GREATER
+ : this((p, c) => executeMethod(p).WaitAsync(c), canExecuteMethod)
+#else
+ : this((p, c) => executeMethod(p), canExecuteMethod)
+#endif
+ {
+
+ }
+
+ ///
+ /// Creates a new instance of with the to invoke on execution
+ /// and a to query for determining if the command can execute.
+ ///
+ /// The to invoke when is called.
+ /// The delegate to invoke when is called
+ public AsyncDelegateCommand(Func executeMethod, Func canExecuteMethod)
+ : base()
+ {
+ if (executeMethod == null || canExecuteMethod == null)
+ throw new ArgumentNullException(nameof(executeMethod), "Neither the executeMethod nor the canExecuteMethod delegates can be null");
+
+
+ _executeMethod = executeMethod;
+ _canExecuteMethod = canExecuteMethod;
+ }
+
+ ///
+ /// Gets the current state of the AsyncDelegateCommand
+ ///
+ public bool IsExecuting
+ {
+ get => _isExecuting;
+ private set
+ {
+ _isExecuting = value;
+ OnCanExecuteChanged();
+ }
+ }
+
+ ///
+ /// Executes the command.
+ ///
+ public async Task Execute(T parameter, CancellationToken? cancellationToken = null)
+ {
+ var token = cancellationToken ?? _getCancellationToken();
+
+ try
+ {
+ if (!_enableParallelExecution && IsExecuting)
+ return;
+
+ IsExecuting = true;
+ await _executeMethod(parameter, token)
+ .ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ throw;
+ }
+ finally
+ {
+ IsExecuting = false;
+ }
+ }
+
+ ///
+ /// Determines if the command can be executed.
+ ///
+ /// Returns if the command can execute,otherwise returns .
+ public bool CanExecute(T parameter)
+ {
+ try
+ {
+ if (!_enableParallelExecution && IsExecuting)
+ return false;
+
+ return _canExecuteMethod?.Invoke(parameter) ?? true;
+ }
+ catch (Exception ex)
+ {
+
+ throw;
+
+ return false;
+ }
+ }
+
+ ///
+ /// Handle the internal invocation of
+ ///
+ /// Command Parameter
+ protected override async void Execute(object parameter)
+ {
+ var cancellationToken = _getCancellationToken();
+ T parameterAsT;
+ try
+ {
+ parameterAsT = (T)parameter;
+ }
+ catch (Exception ex)
+ {
+ throw;
+ }
+
+ // If we had an exception casting the parameter to T ,
+ // we would have already returned. We want to surface any
+ // exceptions thrown by the Execute method.
+ await Execute(parameterAsT, cancellationToken)
+ .ConfigureAwait(false);
+ }
+
+ ///
+ /// Handle the internal invocation of
+ ///
+ ///
+ /// if the Command Can Execute, otherwise
+ protected override bool CanExecute(object parameter)
+ {
+ try
+ {
+ return CanExecute((T)parameter);
+ }
+ catch (Exception ex)
+ {
+ throw;
+ }
+ }
+
+ ///
+ /// Enables Parallel Execution of Async Tasks
+ ///
+ /// The current instance of .
+ public AsyncDelegateCommand EnableParallelExecution()
+ {
+ _enableParallelExecution = true;
+ return this;
+ }
+
+ ///
+ /// Sets the based on the specified timeout.
+ ///
+ /// A specified timeout.
+ /// The current instance of .
+ public AsyncDelegateCommand CancelAfter(TimeSpan timeout) =>
+ CancellationTokenSourceFactory(() => new CancellationTokenSource(timeout).Token);
+
+ ///
+ /// Provides a delegate callback to provide a default CancellationToken when the Command is invoked.
+ ///
+ /// The default Factory.
+ /// The current instance of .
+ public AsyncDelegateCommand CancellationTokenSourceFactory(Func factory)
+ {
+ _getCancellationToken = factory;
+ return this;
+ }
+
+ ///
+ /// Observes a property that implements INotifyPropertyChanged, and automatically calls DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications.
+ ///
+ /// The type of the return value of the method that this delegate encapsulates
+ /// The property expression. Example: ObservesProperty(() => PropertyName).
+ /// The current instance of .
+ public AsyncDelegateCommand ObservesProperty(Expression> propertyExpression)
+ {
+ ObservesPropertyInternal(propertyExpression);
+ return this;
+ }
+
+ ///
+ /// Observes a property that is used to determine if this command can execute, and if it implements INotifyPropertyChanged it will automatically call DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications.
+ ///
+ /// The property expression. Example: ObservesCanExecute(() => PropertyName).
+ /// The current instance of .
+ public AsyncDelegateCommand ObservesCanExecute(Expression> canExecuteExpression)
+ {
+ Expression> expression = Expression.Lambda>(canExecuteExpression.Body, Expression.Parameter(typeof(T), "o"));
+ _canExecuteMethod = expression.Compile();
+ ObservesPropertyInternal(canExecuteExpression);
+ return this;
+ }
+
+ ///
+ /// Provides the ability to connect a delegate to catch exceptions encountered by CanExecute or the Execute methods of the DelegateCommand
+ ///
+ /// TThe callback when a specific exception is encountered
+ /// The current instance of .
+ public AsyncDelegateCommand Catch(Action @catch)
+ where TException : Exception
+ {
+ return this;
+ }
+
+ ///
+ /// Provides the ability to connect a delegate to catch exceptions encountered by CanExecute or the Execute methods of the DelegateCommand
+ ///
+ /// The generic / default callback when an exception is encountered
+ /// The current instance of .
+ public AsyncDelegateCommand Catch(Action @catch)
+ {
+ return this;
+ }
+
+ async Task IAsyncCommand.ExecuteAsync(object parameter)
+ {
+ try
+ {
+ // If T is not nullable this may throw an exception
+ await Execute((T)parameter, _getCancellationToken());
+ }
+ catch (Exception ex)
+ {
+ throw;
+
+ }
+ }
+
+ async Task IAsyncCommand.ExecuteAsync(object parameter, CancellationToken cancellationToken)
+ {
+ try
+ {
+ // If T is not nullable this may throw an exception
+ await Execute((T)parameter, cancellationToken);
+ }
+ catch (Exception ex)
+ {
+ throw;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/29WxOrderWpf/Common/IAsyncCommand.cs b/29WxOrderWpf/Common/IAsyncCommand.cs
new file mode 100644
index 0000000..d54b7c3
--- /dev/null
+++ b/29WxOrderWpf/Common/IAsyncCommand.cs
@@ -0,0 +1,28 @@
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace _29WxOrderWpf.Common
+{
+
+ ///
+ /// Provides an abstraction layer for custom controls which want to make use of Async Commands
+ ///
+ public interface IAsyncCommand : ICommand
+ {
+ ///
+ /// Executes the Command with a specified parameter and the Default .
+ ///
+ /// The Command Parameter
+ /// An Asynchronous Task
+ Task ExecuteAsync(object parameter);
+
+ ///
+ /// Executes the Command with a specified parameter and using a
+ ///
+ /// The Command Parameter
+ /// The .
+ /// An Asynchronous Task
+ Task ExecuteAsync(object parameter, CancellationToken cancellationToken);
+ }
+}
\ No newline at end of file