I have a simple DelegateCommand class that looks like this:
public class DelegateCommand<T> : System.Windows.Input.ICommand where T : class
{
public event EventHandler CanExecuteChanged;
private readonly Predicate<T> _canExecute;
private readonly Action<T> _execute;
public DelegateCommand(Action<T> execute) : this(execute, null)
{
}
public DelegateCommand(Action<T> execute, Predicate<T> canExecute)
{
this._execute = execute;
this._canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
if (this._canExecute == null)
return true;
return this._canExecute((T)parameter);
}
public void Execute(object parameter)
{
this._execute((T)parameter);
}
public void RaiseCanExecuteChanged()
{
this.CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
}
I am using GalaSoft.MvvmLight
for validation and normally I would just do something like this in the View constructor:
this.MyCommand = new DelegateCommand<object>(o => {
//Do execute stuff
}, o =>
{
//Do CanExecute stuff
var validateResult = this.Validator.ValidateAll();
return validateResult.IsValid;
});
public DelegateCommand<object> MyCommand { get; }
This all works great when I have a simple validation check like:
this.Validator.AddRequiredRule(() => this.SomeProperty, "You must select.......");
but now I need a validation method that executes a long running task (in my case a WebService call) so when I want to do somthing like this:
this.Validator.AddAsyncRule(async () =>
{
//Long running webservice call....
return RuleResult.Assert(true, "Some message");
});
and therefore declare the command like this:
this.MyCommand = new DelegateCommand<object>(o => {
//Do execute stuff
}, async o =>
{
//Do CanExecute ASYNC stuff
var validateResult = await this.Validator.ValidateAllAsync();
return validateResult.IsValid;
});
I'm in a bit of a pickle because the standard ICommand implementation doesn't appear to deal with async scenarios.
Without too much thought it seems that you could potentially re-write the DelegateCommand class to support such functionality but I have looked at the way that Prism deals with this https://prismlibrary.github.io/docs/commanding.html, However it seems that they also DO NOT support async CanExecute methods.
So, is there a way around this problem? Or is there something fundamentally broken in trying to run an Async method from CanExecute using ICommand?