I was trying to understand the ICommand interface. I built an application with a button that uses a class called RelayCommand which inherits from ICommand. The class looks like this:
class RelayCommand : ICommand
{
private Action<object> _action;
public RelayCommand(Action<object> action)
{
_action = action;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
if(parameter != null)
{
_action(parameter);
}
else
{
_action("Hello World");
}
}
//We need to include CanExecuteChange when using the Interface ICommand
//In this case it doesn't actually do anything.
public event EventHandler CanExecuteChanged;
}
Everytime I trace the the function, I hit the CanExecute method, but nowwhere in my code am I calling this method. I create a RelayCommand instance like so:
Btn_AcceptedAnswer = new RelayCommand(new Action<object>(AcceptedAnswer_OnClick));
So my question is, when RelayCommand is initiated, how does it know to run CanExecute() and Execute(), and when does it run these? I know how to implement an event, I am just trying to understand how it works.
It is the UI (WPF) that is calling CanExecute
to know whether the button associated to the command must be enabled or not.
Execute
is called when the button is pressed.
You can raise (invoke) the CanExecuteChanged
event when the conditions for CanExecute
change, to inform the UI to requery it. E.g., the command could be a "Clear" command related to a list collection bound to a grid-view, combo-box or the like. If the list changes from empty to non-empty or vice-versa, then raise CanExecuteChanged
. Of course, the button would only be enabled when the list is not empty.
public bool CanExecute(object parameter)
{
return myList.Count > 0;
}
private void OnCanExecuteChanged()
{
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
public void Execute(object parameter)
{
if(myList.Count > 0) {
myList.Clear();
OnCanExecuteChanged();
}
}
When adding elements to the list, you should trigger the event as well. However, this is trickier, as this most likely happens in another command. You will need a way to communicate between the two. A good one would be to use an ObservableCollection<T>
or a BindingList<T>
. Both raise events when the list changes (see: Difference between ObservableCollection and BindingList). The commands could then subscribe the binding list events. An additional effect of BindingList<T>
is that UI-element it is bound to, automatically updates at list changes.