Search code examples
c#wpfcommandcommandbinding

Issue with putting Command CanExecute and Executed handlers out of the main window class


Basically I've got a command binding for the command itself assigned to Window.CommandBindings:

<CommandBinding Command="local:TimerViewModel.AddTimer" 
    CanExecute="local:TimerViewModel.AddTimer_CanExecute" 
    Executed="local:TimerViewModel.AddTimer_Executed" />

local is a namespace generated by default pointing to the namespace of the application. What I'm trying to achieve here is to have the command handling inside the TimerViewModel but I keep getting the following error:

CanExecute="local:TimerViewModel.AddTimer_CanExecute" is not valid. 'local:TimerViewModel.AddTimer_CanExecute' is not a valid event handler method name. Only instance methods on the generated or code-behind class are valid.

The TimerViewModel is pretty simple though but I believe I am missing something:

public class TimerViewModel : ViewModelBase
{
    public TimerViewModel()
    {
        _timers = new ObservableCollection<TimerModel>();
        _addTimer = new RoutedUICommand("Add Timer", "AddTimer", GetType());
    }

    private ObservableCollection<TimerModel> _timers;

    public ObservableCollection<TimerModel> Timers
    {
        get { return _timers; }
    }

    private static RoutedUICommand _addTimer;

    public static RoutedUICommand AddTimer
    {
        get { return _addTimer; }
    }

    public void AddTimer_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = true;
    }

    public void AddTimer_Executed(object sender, ExecutedRoutedEventArgs e)
    {
        _timers.Add(new TimerModel(TimeSpan.FromSeconds((new Random()).Next())));
    }
}

Can anyone point out the mistakes I'm making?


Solution

  • Also take a look at Josh Smith's RelayCommand. Using it would enable you to write the above like this:

    public class TimerViewModel : ViewModelBase {
        public TimerViewModel() {
            Timers = new ObservableCollection<TimerModel>();
            AddTimerCommand = new RelayCommand(() => AddTimer());
        }
    
        public ObservableCollection<TimerModel> Timers {
            get;
            private set;
        }
    
        public ICommand AddTimerCommand {
            get;
            private set;
        }
    
        private void AddTimer() {
            Timers.Add(new TimerModel(TimeSpan.FromSeconds((new Random()).Next())));
        }
    }