8
votes

I'm facing a strange behavior by my asny ICommand implementation when I tried to disable the command while it's executing by default (even when no CanExecute predicate was passed to it).

public bool CanExecute(object parameter)
{
  if (CanExecutePredicate == null)
  {
    return !mIsExecuting;
  }

  return !mIsExecuting && CanExecutePredicate(parameter);
}

public async void Execute(object parameter)
{
  mIsExecuting = true;
  await ExecuteAsync(parameter);
  mIsExecuting = false;
}

I tried to introduce a private bool, which I set to true just before executing and to false afterwards. When execution is finished the bool is set, but CanExecute is only called after I click a mousebutton or move the mouse or w/e.

Now I tried to call

CanExecute(null);

after

mIsExecuting = false;

but that doesn't help neither. I dont know what I'm missing.

Thanks for your help

EDIT:

To clarify I add the constructors for this class aswell:

 public AsyncRelayCommand(Func<object, Task> execute)
  : this(execute, null)
{
}

public AsyncRelayCommand(Func<object, Task> asyncExecute,
               Predicate<object> canExecutePredicate)
{
  AsyncExecute = asyncExecute;
  CanExecutePredicate = canExecutePredicate;
}

protected virtual async Task ExecuteAsync(object parameter)
{
  await AsyncExecute(parameter);
}
1
Where does Execute come into play?Petaflop
When and where you set CanExecutePredicate?Alessandro D'Andria
@AlessandroD'Andria I don't set it, it is always null for nowuser3292642
@user3292642 Sorry but it's not clear to me what's your problem, only thing I can see it's a possible race condition with CanExecutePredicate.Alessandro D'Andria
@AlessandroD'Andria Problem is my GUI is not updated, even tho I call CanExecute(null);. Can you elaborate on that possible race condition?user3292642

1 Answers

10
votes

In async scenarios, WPF tends not to know when to check CanExecute, that's why you have the "CanExecuteChanged" event in the Icommand interface.

You should have something like this in your command implementation:

public event EventHandler CanExecuteChanged
{
    add { CommandManager.RequerySuggested += value; }

    remove { CommandManager.RequerySuggested -= value; }
}

public void RaiseCanExecuteChanged()
{
    CommandManager.InvalidateRequerySuggested();
}

With the code above you can now do this:

public async void Execute(object parameter)
{
    mIsExecuting = true;

    RaiseCanExecuteChanged ( ); // Not necessary if Execute is not called locally

    await ExecuteAsync(parameter);
    mIsExecuting = false;

    RaiseCanExecuteChanged ( );
}

This will tell WPF you want to refresh the CanExecute state of command.