Understanding the Role of Commanding in Silverlight 4 Applications

I’ve had the opportunity to give a lot of presentations on the Model-View-ViewModel (MVVM) lately both publicly and internally for companies and wanted to put together a post that covers some of the frequent questions I get on commanding.  MVVM relies on 4 main pillars of technology including Silverlight data binding, ViewModel classes, messaging and commanding. Although Silverlight 4 provides some built-in support for commanding, I’ve found that a lot of people new to MVVM want more details on how it works and how to use it in MVVM applications.

If you're building Silverlight 4 applications then you've more than likely heard the term "commanding" used at a talk, in a forum or in talking with a WPF or Silverlight developer. What is commanding and why should you care about it? In a nutshell, it's a mechanism used in the Model-View-ViewModel (MVVM) pattern for communicating between a View (a Silverlight screen) and a ViewModel (an object containing data consumed by a View). It normally comes into play when a button is clicked and the click event needs to be routed to a ViewModel method for processing as shown next:

clip_image002


When I first learned about the MVVM pattern (see my blog post on the subject here if you're getting started with the pattern) there wasn't built-in support for commanding so I ended up handling button click events in the XAML code-behind file (View.xaml.cs in the previous image) and then calling the appropriate method on the ViewModel as shown next. There were certainly other ways to do it but this technique provided a simple way to get started.

private void Button_Click(object sender, RoutedEventArgs e)
{
    //Grab ViewModel from LayoutRoot's DataContext
    HomeViewModel vm = (HomeViewModel)LayoutRoot.DataContext;
    //Route click event to UpdatePerson() method in ViewModel
    vm.UpdatePerson();
}


While this approach works, adding code into the XAML code-behind file wasn't what I wanted given that the end goal was to call the ViewModel directly without having a middle-man. I’m not against adding code into the code-behind file at all and think it’s appropriate when performing animations, transformations, etc. but in this case it’s kind of a waste.  What's a developer to do? To answer this question let's examine the ICommand interface.

Using the ICommand Interface

Silverlight 4 adds built-in support for the ICommand interface on any object that derives from ButtonBase (Button, ToggleButton, HyperlinkButton, etc.) allowing the event handler shown earlier to be removed entirely. This results in a cleaner solution and ultimately allows a button click event to be routed directly to a ViewModel method eliminating the middle-man. The following code shows what the ICommand interface looks like. A button can be associated with an object that implements ICommand through the Button control's Command property.

public interface ICommand
{
    bool CanExecute(object parameter);
    void Execute(object parameter);
    event EventHandler CanExecuteChanged;
}

 

The CanExecute() method is used to determine if a command that is associated with a button is allowed to be processed or not. For example, if you're trying to click a button to save customer data, the save button should trigger a commanding call only if all the required data is available. If CanExecute() returns false the button associated with the command (the object implementing ICommand) will automatically be disabled due to the CanExecuteChanged event firing and notifying the button that the command isn't ready to be executed. The Execute() method is used to route processing to a specific ViewModel method such as the UpdatePerson() method shown earlier when all of the required data is available and the command should be executed.

Implementing ICommand

Although Silverlight 4 provides support for the ICommand interface, it doesn't provide a built-in class that implements the interface. As a result you'll either need to write your own or use one of the many classes already out there. I ended up using a class named RelayCommand and RelayCommand<T> from Laurent Bugnion's excellent MVVM Light project available from http://mvvmlight.codeplex.com. The RelayCommand class (visit http://tinyurl.com/DWahlinRelayCommand to view it) implements ICommand and makes it easy to bind a button control's Command property to a ViewModel property and route user actions directly to ViewModel methods for processing. Here's a break-down of how it all works.

Most of us are used to double-clicking a button in the designer to handle the Click event. With commanding you add a property into your ViewModel that implements ICommand and then bind the property to the button control using its Command property. Once the ViewModel object instance is created you'll add code to wire-up the ICommand property to the method that should be called when the button is clicked. In summary, the following steps need to be completed to use commanding in a Silverlight application:

  1. Add an ICommand property into your ViewModel class (I used the RelayCommand class for the sample application since it implements ICommand).
  2. Add code into the ViewModel to wire-up the ICommand property to the ViewModel method that will be called when a button is clicked.
  3. Bind the button to the ViewModel's ICommand property using the Command property.
  4. (Optional) Allow the command to be executed (or not) based upon application rules. The sample code has a customized version of the RelayCommand class that provides an IsEnabled property that can be set to true when the command is ready to execute. The stock version of RelayCommand in MVVM Light allows the command to be executed by default unless you tell it otherwise.

An example of defining an ICommand property (Step 1 above) in a ViewModel is shown next:

public RelayCommand UpdatePersonCommand
{
    get;
    private set;
}

Once the ViewModel is created you need to wire the ICommand property to the method that should be called when the command is executed (Step 2 above). The following code accomplishes this task in the ViewModel's constructor by calling the WireCommands() method.

public class HomeViewModel
{
    public HomeViewModel()
    {
        WireCommands();
    }

    public RelayCommand UpdatePersonCommand
    {
        get;
        private set;
    }

    void WireCommands()
    {
        UpdatePersonCommand = new RelayCommand(UpdatePerson);
        //Wire up other commands here
    }

    public void UpdatePerson()
    {
        //Code to update the current person object
    }
}

Finally, the target button control must be bound to the ICommand property defined in the ViewModel using its Command property (Step 3 above):

<Button Command="{Binding UpdatePersonCommand}" 
        Content="Submit" 
        Height="20" 
        Width="100" 
        HorizontalAlignment="Left" />


As the user clicks the button the ViewModel's UpdatePerson() method will be called directly. While commanding isn't quite as simple as double-clicking on a button and handling the Click event, it provides a great way to separate concerns, keep code clean and hook Views directly to ViewModel methods.

Using Button's CommandParameter Property

Although I rarely need it, ButtonBase also exposes a CommandParameter property that can be used to pass a parameter value to a method. I normally access View control values directly through properties in the ViewModel which is why I don't use CommandParameter much. The CommandParameter property can be bound to control values using standard data binding techniques as shown next:

<Button Command="{Binding UpdateFirstNameCommand}" 
        CommandParameter="{Binding ElementName=FirstNameTextBox, Path=Text}" 
        Content="Update" />


In this example the text value from a text box named FirstNameTextBox is passed when the button is clicked. The code that follows shows how the ViewModel command property changes when a parameter needs to be passed to a method using ButtonBase's CommandParameter property. Note that a generic version of RelayCommand is used (available with MVVM Light and in the sample code) so that the data can be passed in a strongly-typed manner.

public RelayCommand<string> UpdateFirstNameCommand
{
    get;
    private set;
}

void WireCommands()
{
    UpdateFirstNameCommand = new RelayCommand<string>(fname => UpdateFirstName(fname));
}

private void UpdateFirstName(string fname)
{
    //Add code here to perform update
}

Commanding works very well once the different pieces are in place but what happens if some of the events firing in your Views are triggered by controls that don't derive from ButtonBase? We'll need to call in reinforcements to handle that situation.

Using Blend's InvokeCommandAction

Expression Blend 4 offers an InvokeCommandAction that can be used to hook events from controls that don't derive from ButtonBase directly to ViewModel methods. This is extremely useful in applications that need to communicate between View and ViewModel classes using controls other than Button, HyperlinkButton, etc. For example, you may create a menu composed of multiple StackPanel controls each containing Image and TextBlock controls. As the user clicks on one of the menu items you may want to invoke a ViewModel method. Using the approach shown earlier you can't do this since there's no Command property on StackPanel, Image, TextBlock or any other control that doesn't derive from ButtonBase. Fortunately, Blend's InvokeCommandAction can be used instead.

Associating InvokeCommandAction with a Silverlight control event can be done directly in XAML or visually in Expression Blend. If you don't have a Blend license you can get everything you need by downloading the Expression Blend SDK for Silverlight 4 (get it here) which includes the System.Windows.Interactivity.dll assembly needed to use InvokeCommandAction.

If you'll be typing the XAML by hand you'll first want to add a reference to System.Windows.Interactivity.dll (available in the Blend SDK) into your Silverlight project in order to use the trigger and action features. Once that's done you can add a namespace and assembly reference onto the root XAML tag as shown next:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"


Once the namespace prefix is added you can add the XAML shown next within the element that will raise an event that needs to be routed to the ViewModel. The following code handles the MouseLeftButtonUp event of a StackPanel and binds it to an ICommand property in the ViewModel named AddPersonCommand. Any type of event can be associated with a command property using the EventTrigger element's EventName property.

<StackPanel Orientation="Horizontal" Cursor="Hand">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseLeftButtonUp">
            <i:InvokeCommandAction Command="{Binding AddPersonCommand}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
    <Image Source="/SilverlightDemos;component/Assets/Images/add.png" Margin="0,0,0,0"/>
    <TextBlock Text="Add" FontWeight="Bold" 
               VerticalAlignment="Center"  
               HorizontalAlignment="Left" 
               Margin="5,0,0,0" />
</StackPanel>


If you have a copy of Expression Blend 4 you can go to the asset window, search for InvokeCommandAction, and then drag and drop it onto a target control such as StackPanel. From there you can go to the properties window to select the proper event and bind the Command property to a ViewModel property that supports ICommand. Here’s what the property window looks like in Blend after the EventName has been picked.

image

Although there’s even more that could be discussed when it comes to commanding, you’ve seen the key parts in this post including the ICommand interface, a class that implements ICommand (such as RelayCommand), defining ICommand properties and binding buttons and other types of controls to ViewModel command properties. If you’re brand new to MVVM and the concept of commanding it’ll take a little time to get used to since it’s very different from what we did in ASP.NET or Windows forms applications. However, I can tell you from experience that it’s well worth the time it takes to get used to and becomes second nature after a little practice.

Download the sample application associated with this post below.

image_418B5BFB1_47FBF5721_75802FD51_32D302891_660557911_31FF066B1_7239488E[1]

 

Download

 

If you or your company is interested in training, consulting or mentoring on Silverlight 4 or other .NET technologies please visit http://www.thewahlingroup.com for more information. We’ve provided training, consulting and mentoring services to some of the largest companies in the world and would enjoy sharing our knowledge and real-world lessons learned with you.

comments powered by Disqus

7 Comments

  • Its a SuperPost to complement implementation of MVVM in the neatest and simplest way.

    Thank you.

    KRK

  • Can you explain this type of syntax?

    ServiceAgent.GetPeople((s,e) =>
    {
    People = e.Result;
    });


    ServiceAgent.CallService((s, e) =>
    {
    PeopleEventBus.OnOperationCompleted(this, new OperationCompletedEventArgs { OperationStatus = e.Result });
    }, CurrentPerson);


    The lambda expression has me confused. thanks -dave

    or

  • David,

    Glad you downloaded the code and took a look. The first example shows how the WCF proxy can be called directly whereas the second shows a more re-useable solution I use in real apps to minimize the amount of code that has to be written.

    Instead of supplying a callback method I handle the callback directly using the lambda. Let me break it down in case others read this and want more details as well (keep in mind that the following discussion doesn't have anything to do with the commanding topic covered in this post....it's just part of the sample code). &nbsp;

    I could've done the following which would be fine but adds a distinctly separate method into the mix (nothing wrong with that by the way...just not my preference). ServiceAgent serves as a wrapper class in this example and allows you to specify a callback function as a parameter to GetPeople():

    ServiceAgent.GetPeople(MyCallback);

    void MyCallback(object s,GetPeopleEventArgs e)

    {

    &nbsp; &nbsp;People = e.Result;

    }

    By using the lambda I'm able to create an anonymous method right there at the GetPeople() call which makes things easier to read I think (once you get used to lambdas that is). &nbsp;The s parameter from the lambda matches up with s in MyCallback() and the e parameter from the lambda matches up with e in MyCallback(). You can name the parameters whatever you want though with lambdas. The same principles apply CallService&lt;T&gt;() method which also uses a lambda to embed an anonymous callback method.

    Hope that helps,

    Dan

  • Can InvokeCommandAction be used on buttons as well - or anything - ie. a combobox onSelect ?

  • Steve,

    I haven't tried it on buttons since anything deriving from ButtonBase already has a Command property that can be used but it should work fine there. Definitely works well on other controls such as ComboBox, etc.

    Dan

  • great post dan! helped me getting started with commanding a lot!

  • Glad it helped you out!

    Dan

Comments have been disabled for this content.