Using RelayCommands in Silverlight 3 and WPF

.NET, Blend, MVVM, Silverlight, Work, WPF
No Comments

This post was imported from my old blog and had 43 comments which are included as a screenshot at the end of this post.

Like most of us have found out the hard way, Silverlight 3 and Windows Presentation Foundation 3.5 are two quite similar beasts, but not totally the same. Silverlight is often presented as a subset of WPF (in fact, some features are available in Silverlight but not yet in WPF; generally speaking, though, it is true that Silverlight has less features than its big sister WPF) (yeah WPF is a girl, don’t tell me you didn’t know ;) )


No Commands in Silverlight 3

One of the missing parts is Commanding. Commands in WPF are used as a kind of “weak events”, i.e. they can be used to execute an action when a control is actuated (just like an event), but without the tight coupling that an event brings with it. You can specify a Command on an object, and bind this command to a control in a completely different part of your application. You can have one person write the Command (typically a developer), and a completely other person (typically a designer) use the Command in the user interface. More interestingly, the designer can change the look and feel, for example replacing a series of Buttons by a Menu and MenuItems, and the developer doesn’t need to change anything to the code.

In Silverlight, parts of the “plumbing” are available already (the ICommand interface) but most of it is missing. This led some very clever people to implement Commands in Silverlight, to replace the missing pieces by a custom implementation. In Prism, the command implementation is called DelegateCommand. In my MVVM Light Toolkit, I use a command that my good friend, colleague at IdentityMine and fellow WPF Disciple Josh Smith created, called the RelayCommand.

Now, the beautiful part is that RelayCommands (and DelegateCommands too) work wonders in Silverlight, but also in WPF. RelayCommands are making your life much easier in WPF too. No need to implement complicated code to bind the control to your method, just use a RelayCommand to do that. And since the implementation is (almost) the same in Silverlight too, you can share code between Silverlight and WPF.

The Execute Method

When the control to which a Command is bound is actuated by the user, the Execute method is called. This method is specified by the ICommand interface, and every ICommand implementation must offer it (and of course RelayCommand does).

The Execute method is passed to the RelayCommand’s constructor in form of an Action (or Action<T> if the command has a parameter, in which case you must use the RelayCommand<T> class).

Note: An Action is a method  (returning void) that can be passed to another object, for example as a parameter. It is something like a method pointer. If the method that the Action represents has a parameter, you must use Action<T> where T is the parameter’s type. There are also additional Action implementations with more than one parameters, but RelayCommand can only have 0 or 1 parameter.

The code to create a RelayCommand is:

public RelayCommand MyCommand
{
    get;
    private set;
}

public MainViewModel()
{
    MyCommand = new RelayCommand(
        () => DoSomething());
}

Note: The syntax () => DoSomething() is called a lambda expression, and is the shortest way to define and pass an Action to an object. In the sample here, the method DoSomething will be called without any parameter when the Command is executed.

CanExecute and CanExecuteChanged

Apart from the Execute method that the ICommand interface specifies, there is an additional method and an event that every ICommand (including, of course, RelayCommand) must offer.

  • CanExecute: This method should return true if the command can be executed. When the Command is used on a control, the control will be disabled automatically when CanExecute returns false.
  • CanExecuteChanged: This event should be raised when the CanExecute method must be “requeried” (when the value of CanExecute might have changed, and should be re-evaluated).

The CanExecute method can be passed to the RelayCommand constructor as a Func<bool> (or a Func<T, bool> if the command has a parameter).

Note: A Func is exactly like an Action, except that it has a return type. In the case of RelayCommands, the return type is bool: True if the command can be executed, false otherwise.

To create a command with an Execute and a CanExecute methods, you can do:

public RelayCommand MyCommand
{
    get;
    private set;
}

public MainViewModel()
{
    MyCommand = new RelayCommand(
        () => DoSomething(),
        () => return MyValue);
}

In the code above, if MyValue is true, the command can be executed; if it is false, the command cannot be executed (and controls using that command are disabled). This can depend on multiple parameters such as the state of the application, the time of the day, the weather outside, etc.

Note: When using lambda expressions, if the expression is just “return something”, the “return” keyword can be omitted. So the code becomes:

public RelayCommand MyCommand
{
    get;
    private set;
}

public MainViewModel()
{
    MyCommand = new RelayCommand(
        () => DoSomething(),
        () => MyValue);
}

The CommandManager

RelayCommands are available for WPF and Silverlight. However, one piece is missing in Silverlight: Windows Presentation Foundation has a class that is watching your UI, and that polls the commands’ state when something happens (for example when the user clicks a button, checks a checkbox, open a menu, etc…). This class is called the CommandManager and it doesn’t exist in Silverlight. Not at all. Nada.

So when a user actions the UI in WPF, this triggers the CommandManager to requery all the commands. In Silverlight you have to do the work yourself. This is why the RelayCommand class has a method called RaiseCanExecuteChanged. This method forces the control that uses the command to check again if the command may be executed or not. And if the command may not be executed, the control is disabled.

In WPF

Strictly speaking, in WPF, and if your command is bound to a control that is watched by the CommandManager, you shouldn’t have to raise the CanExecuteChanged event yourself. You can let the CommandManager handle the situation. That said, external events might also change the state of the UI. Let’s imagine that the UI should be enabled from 9AM to 5PM, and then disabled for the night. The user is not triggering the UI, so the code should request (politely) that the CommandManager requeries the state of the commands. This is done by calling the method InvalidateRequerySuggested on the CommandManager. And as you guessed, the method RaiseCanExecuteChanged of the RelayCommand class does just that.

And in Silverlight

However, since Silverlight doesn’t have the CommandManager, a little more manual work is involved. When the state of your object changes in a way that affects the UI, you must RaiseCanExecuteChanged on the corresponding commands. In Silverlight, this will raise the CanExecuteChanged event, thus forcing the bound controls to call CanExecute. In WPF,  like we just saw, this will call InvalidateRequerySuggested on the CommandManager.

Show me the code

I created a small demo to illustrate this in Silverlight and in WPF, using the MVVM Light Toolkit. Most of the code is shared between WPF and Silverlight. The source code for the application is available as usual (WPF 3.5 SP1 and Silverlight 3).

The demo exposes one command, created in the MainViewModel class:

public RelayCommand IncreaseCounterCommand
{
    get;
    private set;
}

public MainViewModel()
{
    IncreaseCounterCommand = new RelayCommand(
        () => Counter++,
        () => CanIncrement);
}

The Counter and CanIncrement properties are raising the PropertyChanged event when they are modified, thus data bindings that refer to these two properties will be updated whenever the properties are modified. What the code above means is: When the IncreaseCounterCommand is executed, check the CanIncrement property. If it is true, increment the Counter property.

2009092601

Figure 1: WPF demo application, Enabled and Disabled

Disabling the button

We have a manual way to enable/disable the “increment” button: If you click on the “Enabled” text, it will turn into “Disabled”. This text (it’s a ToggleButton) is bound to the CanIncrement property directly. So in fact, when the text is “Disabled”, the CanIncrement property is set to false.

Of course, we want the controls using this command to be automatically disabled/enabled when the CanIncrement property changed. In WPF, nothing needs to be done, because the CommandManager will automatically requery the state of the commands when the user clicks on the UI. In fact the state of the commands is requeried very, very often during the course of the application. Even just moving the mouse on the UI causes the CommandManager to requery the state of commands bound to visible UI element.

In Silverlight however, no CommandManager, so we need to raise the CanExecuteChanged event on the command manually. Note that raising the CanExecuteChanged event can be useful in WPF too if you change the CanIncrement property in the code, for example through a timer. So, in fact, we will just call IncreaseCounterCommand.RaiseCanExecuteChanged() in Silverlight and in WPF too when CanIncrement changes:

public bool CanIncrement
{
    get
    {
        return _canIncrement;
    }

    set
    {
        if (_canIncrement == value)
        {
            return;
        }

        _canIncrement = value;

        // Update bindings, no broadcast
        RaisePropertyChanged(CanIncrementPropertyName);

        IncreaseCounterCommand.RaiseCanExecuteChanged();
    }
}

Just a warning: In V1 of the MVVM Light Toolkit, the method RaiseCanExecuteChanged was taking a boolean parameter. This boolean was actually not very useful, and has been removed in V2. Calling the old method still works in V2, but the parameter has no effect, and the method has been marked Obsolete. It will be removed in a future version of the toolkit.

This sample uses V2 beta of the MVVM Light Toolkit.

Silverlight/WPF Compatibility

Much of the code is shared between Silverlight and WPF in this small demo.

  • The ViewModel code is completely shared. The source code files are physically into the WPF project, and added as links into the Silverlight project. Implement once, compile twice.
    To add a source code file as a link, choose “Add existing item” in Visual Studio. Then, select a file. Instead of clicking on Add, click on the arrow on the right of the Add button, and select “Add as a link”.
  • The resources defining the look&feel of the application are placed into the file Skins\MainSkin.xaml. The code n this file is 100% the same in WPF and in Silverlight. To reuse the Silverlight control templates in WPF too, I use the WPF Toolkit’s implementation of the Visual State Manager.
  • Finally, the XAML code in the main UI element (MainWindow.xaml in WPF, and Page.xaml in Silverlight) is almost the same, except for one little difference: Since Silverlight doesn’t support commands out of the box, we rely on an attached behaviour to bind the RelayCommand to the Button:
<Button cmd:ButtonBaseExtensions.Command="{Binding IncreaseCounterCommand}"
        Grid.Row="2"
        Style="{StaticResource IncrementButtonStyle}"
        Content="Increment" />

Conclusion

Commands in WPF are quite a complex topic, and I must admit that I didn’t completely understand them before I discovered the RelayCommand class. I totally fell in love with this fantastic helper. Josh Smith has been fantastic in allowing me to re-use his code in the MVVM Light Toolkit. I hope that this article will help you understand the power and convenience of RelayCommands. Happy coding!

GalaSoft Laurent Bugnion
Laurent Bugnion (GalaSoft)

Share on Facebook

This post was imported from my old blog. Original comments screenshot: 12-22-2013 11-36-41 PM

Leave a Reply