24

I've just started learning the MVVM Light framework and I can't find any straightforward examples on how to use a RelayCommand. For purposes of learning, I'd just like to have a button in my view which when clicked show's a hello world world message box, and which is enabled on every even minute (basically if DateTime.Now.Minute % 2 == 0).

How would the button XAML look and how would the RelayCommand HelloWorld be defined in the ViewModel?

Thanks for your help!!

Evan
  • 4,450
  • 10
  • 40
  • 58

2 Answers2

48

RelayCommand's purpose is to implement the ICommand interface that Button controls needs and to just pass the calls onto some other function which generally sits right next to them in the ViewModel.

So for example, you would have a ViewModel class like:

class HelloWorldViewModel : ViewModelBase
{
    public RelayCommand DisplayMessageCommand { get; private set; }

    private DispatchTimer _timer;

    public HelloWorldViewModel()
    {
        this.DisplayMessageCommand = new RelayCommand(this.DisplayMessage, CanDisplayMessage);

        // Create a timer to go off once a minute to call RaiseCanExecuteChanged
        _timer = new DispatchTimer();
        _timer = dispatcherTimer.Tick += OnTimerTick;
        _timer.Interval = new Timespan(0, 1, 0);
        _timer.Start();
    }

    private void OnTimerTick(object sender, EventArgs e)
    {
        this.DisplayMessageCommand.RaiseCanExecuteChanged();
    }

    public bool CanDisplayMessage()
    {
        return DateTime.Now.Minute % 2 == 0;
    }

    public void DisplayMessage()
    {
        //TODO: Do code here to display your message to the user
    }
}

In your control you would have the DataContext set either in the code behind or in the XAML directly through a DataContext={StaticResource ...}

Your button would then bind to the command in the ViewModel like so

<Button Content='Push me' Command='{Binding DisplayMessageCommand}' />

When the Button is clicked, it uses the DisplayMessageCommand and calls Execute() on this object which RelayCommand just forwards onto the DisplayMessage method.

The DispatchTimer goes off once a minute and calls RaiseCanExecuteChanged(). This allows the button which is bound to the command to re-check if the command is still valid or not. Otherwise, you might click the button only to find out that the command isn't currently available.

Josh Bowden
  • 5,735
  • 2
  • 25
  • 36
MerickOWA
  • 7,453
  • 1
  • 35
  • 56
  • Just out of curiosity, is there a way to bind the command's CanDisplayMessage() to the IsEnabled property? – Evan Jul 19 '11 at 22:28
  • @evan, if you mean the IsEnabled property of the Button? This is automatically done if you set the Command object on the Button – MerickOWA Jul 19 '11 at 22:32
  • 5
    In addition to the very complete example here, note the following: - You can use lambda expressions as delegates in case you don't want to name your Execute and CanExecute methods. - In addition to the Command property on all ButtonBase controls (Button, RadioButton, CheckBox etc), you can also use the EventToCommand behavior (available in MVVM Light "extras") to bind any event to a command. – LBugnion Jul 20 '11 at 19:24
  • @LBurgnion - thanks for pointing out EventToCommand, that's great to know! – Evan Jul 21 '11 at 18:23
  • Let me fix that for you ... `public ICommand DisplayMessageCommand { get; private set; }` – hyankov Sep 04 '17 at 07:00
5

Or with lambda

    private RelayCommand<anyobject> _AddCmd;
    public ICommand AddPoint
    {
        get
        {
            return _AddCmd ??
                (
                _AddCmd = new RelayCommand
                    (
                        (obj) =>
                        {
                            ViewModelWF.ZeroPoints.Add(new WM.Point(0, 0));
                        }
                    )
                );
        }
    }

    private RelayCommand _DeleteCmd;
    public ICommand DeletePoint
    {
        get
        {
            return _DeleteCmd ??
                (
                _DeleteCmd = new RelayCommand
                    (
                        () =>
                        {
                            int idx = wpfZeroPoints.SelectedIndex;
                        },
                        () =>
                        {
                            return wpfZeroPoints.SelectedIndex <= 0;
                        }
                    )
                );
        }
    }
Romano Zumbé
  • 7,893
  • 4
  • 33
  • 55