I got a WPF application that shows a button bound to a command like that:
<Button Command="{Binding Path=TestrunStartCommand}" Content="GO!">
The command is defined like that:
public ICommand TestrunStartCommand
{
get { return new RelayCommand(TestrunStartExecute, () => !IsTestrunInProgress); }
}
public bool IsTestrunInProgress
{
get{
return _isTestrunInProgress;
}
set{
_isTestrunInProgress = value;
RaisePropertyChanged(IsTestrunInProgressPropertyName);
}
}
The problem is, the button won’t be enabled immediately after I set IsTestrunInProgress to false, but only after I click inside the application window.
Could you help me understand this behaviour and show me how to fix this?
Further reading:
wpf command pattern – when does it query canexecute
The
ICommandinterface exposes an eventICommand.CanExecuteChangedwhich is used to inform the UI when to re-determine theIsEnabledstate of command driven UI components.Depending upon the implementation of the
RelayCommandyou are using, you may need to raise this event; Many implementations expose a method such asRelayCommand.RaiseCanExecuteChanged()which you can invoke to force the UI to refresh.Some implementations of the
RelayCommandmake use ofCommandManager.RequerySuggested, in which case you will need to callCommandManager.InvalidateRequerySuggested()to force the UI to refresh.Long story short, you will need to call one of these methods from your property setter.
Update
As the state of the button is being determined when the active focus is changing, I believe the
CommandManageris being used. So in the setter of your property, after assigning the backing field, invokeCommandManager.InvalidateRequerySuggested().Update 2
The
RelayCommandimplementation is from the MVVM light toolkit. When consumed from WPF/.NET, the implementation wraps the methods and events exposed from theCommandManager. This will mean that these commands work automagically in the majority of situations (where the UI is altered, or the focused element is changed). But in a few cases, such as this one, you will need to manually force the command to re-query. The proper way to do this using this library would be to call theRaiseCanExecuteChanged()method on theRelayCommand.