In the demo, I have a button to toggle a bool field isAsking
. I create a command which can execute only when isAsking==true
.
Once I press T
To expand a comment by Default
Suppose we have the following
public class SomeClass : ViewModelBase {
public ICommand ConnectButtonCommand { get; }
public SomeClass(){
//...
ConnectButtonCommand = new DelegateCommand(ConnectButton_Click, ConnectButton_CanExecute);
//...
}
public DoSomething(){
//do something that affects the result of ConnectButton_CanExecute
((DelegateCommand)ConnectButtonCommand).RaiseCanExecuteChanged();
}
private void ConnectButton_Click() {/*...*/}
private bool ConnectButton_CanExecute() {/*...*/}
}
I am working on a UWP app that uses Prism for MVVM. Universal windows platform is very similar to WPF.
I try to search for "the CommandManager detects conditions" and reach this exellent article.
By examining .NET Framework source code, the author finds that the CommandManager
doesn't detect conditions by itself, rather than when Keyboard.KeyUpEvent
, Mouse.MouseUpEvent
, Keyboard.GotKeyboardFocusEvent
, or Keyboard.LostKeyboardFocusEvent
occurs, it will reevaluate CanExecute method.
The article includes other information, but the above part has been enough for me.
The technical answer is that CanExecute
will be invoked whenever the CommandManager.RequerySuggested event is raised. According to the documentation, this will be...
...when the CommandManager detects conditions that might change the ability of a command to execute.
In practical terms, this just means that you don't need to worry about when CanExecute
is called: WPF will invoke it when it thinks it is appropriate, and in my experience this will almost always cover your requirements.
The exception to this is if you have a background task that will cause CanExecute
to change it's return value based on something that is not triggered by the UI. In this scenario, you may need to manually force the WPF runtime to re-query CanExecute
which you can do by calling CommandManager.InvalidateRequerySuggested
RoutedCommand
contains an event CanExecuteChanged
which internally hook to the CommandManager.RequerySuggested
event -
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
And CommandManager.RequerySuggested
event is raised
whenever changes to the command source are detected by the command manager which is in your case is Window. So, when button is clicked, commandManager raised the RequerySuggested event and hence executed the CanExecute predicate registered for your command.
Also, CommandManager has a static method - InvalidateRequerySuggested
which forces the CommandManager to raise the RequerySuggestedEvent. So, you can call that to validate your commands too manually.