2

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?

Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Johnny
  • 889
  • 2
  • 13
  • 24

2 Answers2

2

Take a look at http://www.wpftutorial.net/DelegateCommand.html for an example of how to implement the delegate command for WPF. It allows you to hook up Execute and CanExecute as event handlers. If you're using RoutedUICommand directly you need to derive a custom command from it and override Execute and CanExecute with your functions.

Wayne Tanner
  • 1,346
  • 11
  • 18
  • I'm willing to make a custom command, but I'm kinda lost in the manner of knowing how to do so. Any advice/links? – Johnny Nov 13 '11 at 16:58
2

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())));
    }
}
ssarabando
  • 3,397
  • 2
  • 36
  • 42
  • That's... Really nice! I do not yet fully understand how does it work, and I'm itching to find out before implementing it, but this is too neat not to implement! Thanks! – Johnny Nov 13 '11 at 17:26
  • As I presumed it seems to need some additional code... Seemingly the 'new RelayCommand(AddTimer);' isn't doing the trick as it warns me that: Argument 1: cannot convert from 'method group' to 'System.Action' – Johnny Nov 13 '11 at 17:32
  • Sorry, my bad. Write it as `() => AddTimer()` instead; I'll update the code above. – ssarabando Nov 13 '11 at 17:40
  • Figured it out, tho for the one I found the proper usage would be (object x) => AddTimer(x) Still I've managed to do it, but right now I'm struggling to make it bind to the button. Command="AddTimerCommand" would be the right approach or? Because with that it says 'cannot convert AddTimerCommand'... EDIT: My bad. Should have wrote Command="{Binding AddTimerCommand}". Thanks for your assistance! – Johnny Nov 13 '11 at 18:06