Thursday, March 17, 2011

MVVM Light for Silverlight Part 3: Commands

- We are going take a look at Commands in SL4 and find out how they can help us accomplish some goals in an MVVM application.

Tools: VS2010 | C# | Silverlight 4 | Blend 4 | MVVM Light Toolkit V3 SP1

MVVM Light for Silverlight Series Index:
Part : Introduction, Part 2: The Glue


Commands

We are going take a look at Commands in SL4 and find out how they can help us accomplish some goals in an MVVM application. Commands allow you to associate an action to a control through the use of binding. If your not very familiar with Commands in SL4 there are plenty of references like this one on the net.  It is not necessary to know Commands in detail in order to follow along. I would encourage you to learn what you can about commands in SL4 if you haven't done so already. It is not necessary to have read the previous two posts in the series to follow along with part 3, but if you need to get up to speed on MVVM Light and the Basics you may want to check out Part 1 and Part 2.

Agenda

Overview
Basic Implementation
Update a Property
CanExecute
Passing a Parameter

Overview

Commands allow you to attach an action to a control without wiring an event and associated code behind, like in a typical Button.Click() scenario. Your still going to have to associate the command with something in code if you want it to do anything, but you dont have to do it in the xamls code behind file. Typically you would have to attach a click event handler to the button in xaml or code behind and write the code for that event right there in the code behind. With commands you can bind a Command to a button and it will execute the command when the button is clicked. The action code does not have to be in the code behind of the xaml file your where you are binding the command. MVVM Light implements commands using the RelayCommand class. This class inherits from the ICommand interface, which is necessary if you want to implement support for commanding. More detailed information on RelayCommand in MVVM Light can be found here. Details on ICommand here. To quote Microsoft:
"The ICommand interface enables the abstraction of a parameterized method call through its Execute method. In addition, you determine whether a method can be called prior to calling it with the CanExecute method.

Typically objects implement this interface to enable method calls on the objects through the use of XAML bindings. This is particularly useful in Model-View-ViewModel (MVVM) scenarios, as it allows models to expose commands to which controls such as buttons can be bound to without requiring additional code.

Silverlight 4 implements a limited commanding surface area, rather than an entire commanding infrastructure that is equivalent to commanding in WPF. The classes that support command-initiated user interaction are the following:
  
      ButtonBase   

      Hyperlink

You can bind the Command property of these objects and their derived classes to instances of objects that implement ICommand. In addition, the ICommand interface exists for compatibility, which is helpful if control authors migrate WPF code-defined or particularly markup-defined command bindings for a Silverlight implementation." - Microsoft
Basic Implementation

We are first going to implement a simple command. Fire up an MVVM Light project and use the MVVM SL4 project template. Open MainPage.xaml (the View). Lets go ahead and put a button in there under the welcome message. We will later use this button for our command binding.

<Grid x:name="LayoutRoot">

    <Textblock fontsize="36" fontweight="Bold" foreground="Purple" horizontalalignment="Center" text="{Binding Welcome, Mode=TwoWay}" textwrapping="Wrap" verticalalignment="Center"/>

    <Button content="Command Test" margin="45,226,42,12"></Button>

</Grid>

Next we are going to open the MainViewModel.cs and create a RelayCommand inside the MainViewModel class as follows:

public RelayCommand TestCommandBasicRC
{
   get;
   private set;
}

This simply creates a bare-bones RelayCommand definition named TestCommandBasicRC. If the type 'RelayCommand' cannot be found, you will need to add the following using declaration.

using GalaSoft.MvvmLight.Command;

Next we are going to define a function that is executed when our command has been triggered. This is where we write the code that gets executed when the button is clicked.

// TestCommandBasic - simple command test
private void TestCommandBasic()
{
    MessageBox.Show("TestCommandBasic");
}

In the MainViewModel constructor we are going to define and pass an action to our object using a lambda expression. Here we are passing the function TestCommandBasic() that we just defined. This function will be called when our Command is executed.

public MainViewModel()
{
    TestCommandBasicRC = new RelayCommand(() => TestCommandBasic());
}

Now our command is setup. The last thing we need to do is hook up the button with our new command. Open MainPage.xaml and add the command property to our button and bind it to our new TestCommandBasicRC command so that it looks like this:

<Button command="{Binding TestCommandBasicRC}" content="Command Test" margin="45,226,42,12"></Button>

Run the project and click the button. A message box should pop up displaying the message we provided inside the function we wrote that is called by our command.

To quickly recap, all you need to do in order to utilize Commanding is to create a Command, initialize it, and bind the Command to a control. Any control inheriting from ButtonBase or Hyperlink class would be capable of Commanding.

As you can see, using Commands is a great way to execute an action that calls code from a ViewModel. Now that you know the basics I will show you a few more things about Commands.

Update a Property

One common scenario you will likely run into is updating a property when a Command is executed. What we will do in this next example is update a property when our Command is executed and then call the 'RaisePropertyChanged()' function inside our property setter. This will essentially update anything bound to this property. First create a new MVVM Light Project from the SL4 Template and then open MainViewModel.cs so we can setup the property.
Quick Bonus: Laurent released some code snippets along with the MVVM Light framework. You can download them from his site and put them in your VS2010 code snippets folder. You can access the snippets in code by typing mvvm and choosing 'mvvminpc'. After you select this option you can press the TAB button and it will create the property structure for you.
Let us first create a property to test with. Use the following:

public const string TestPropertyPropertyName = "TestProperty";
private string _testProperty = "test property string";

public string TestProperty
{
    get
    {
        return _testProperty;
    }

    set
    {
        if (_testProperty == value)               
            return;               

        _testProperty = value;
       
        // Update bindings, no broadcast
        RaisePropertyChanged(TestPropertyPropertyName);
    }
}

The property should look like the above when you are done. If you are using the snippet you may notice I deleted some things that were not needed for this property. It is pretty straight forward. We call the RaisePropertyChanged() method after we set the property value. Now that we have the property setup, lets setup the command that will execute and call a function that will set this property.

public RelayCommand TestCommandPropertyUpdateRC
{
    get;
    private set;
}

Now setup the function that will be called by our command. We will simply change the property value so that we know the property has been changed and should be updated.

// TestCommandPropertyUpdate -
private void TestCommandPropertyUpdate()
{           
    TestProperty = "Property Updated";
}

Lets again initialize our command in the ViewModel constructor:

public MainViewModel()
{
    TestCommandPropertyUpdateRC = new RelayCommand(() => TestCommandPropertyUpdate());
}

Now the only thing left to do is the View so open MainPage.xaml. For this property update test we are simply going to update the default welcome message to bind to our new property 'TestProperty', and bind our 'TestCommandPropertyUpdateRC' command to a button so we can execute the command.

<Grid x:name="LayoutRoot">
    <TextBlock fontsize="36" fontweight="Bold" foreground="Purple" horizontalalignment="Center" text="{Binding TestProperty, Mode=TwoWay}" textwrapping="Wrap" verticalalignment="Center"></Textblock>

    <Button command="{Binding TestCommandPropertyUpdateRC}" content="Command Property Update" margin="45,226,42,12"></Button>

</Grid>

Run the application and click the button. The command should be executed and the TextBlock should be updated to reflect a new string value: 'Property Updated'. Thats all there is to it.

CanExecute

You may come across a scenario where you only want the command to be executed based on a condition, this is where CanExecute comes into play. When initializing a RelayCommand you have the option to pass in a condition that will let your command know if it should execute when it is called.In addition to simply being a flag for execution, it also disables the control that the command is bound to.

Lets try an example. Fire up a new MVVM Light Project from the SL4 Template and then open MainViewModel.cs. Lets create a new RelayCommand

public RelayCommand TestCommandCanExecuteRC
{
    get;
    private set;
}

Next we are going to create a property that will be used as our CanExecute flag. You can once again use the shortcut snippet above mvvminpc to setup this property and make it look like this:

public const string CanExecutePropertyName = "CanExecute";
private bool _canExecute = false;

public bool CanExecute
{
    get
    {
        return _canExecute;
    }

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

        _canExecute = value;

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

        TestCommandCanExecuteRC.RaiseCanExecuteChanged();
    }
}

Inside this property setter we have something new going. We are calling the RaiseCanExecuteChanged() method on our Command. This will let our Command know that our CanExecute property has changed and should be evaluated again to determine state.

Next we will setup the function to be called by our command. This function will only be called if our CanExecute flag returns true. Put in the following code:

// TestCommandCanExecute -
private void TestCommandCanExecute()
{
    MessageBox.Show("Command Executed");
}

Now lets initialize the command. Notice here how we are passing a second parameter. A RelayCommand can be instantiated with or without the CanExecute parameter.

TestCommandCanExecuteRC = new RelayCommand(() => TestCommandCanExecute(), () => CanExecute);

Now all thats left is the View. Lets head to the MainPage.xaml and create a quick View. We are simply going to use a toggle button for toggling the CanExecute state, and a Button for calling our new Command. It looks like this:

<Grid x:name="LayoutRoot">

    <StackPanel verticalalignment="Center">
        <ToggleButton content="Toggle Can Execute" ischecked="{Binding CanExecute, Mode=TwoWay}">
        <Button command="{Binding TestCommandCanExecuteRC}" content="Command Execute"/>
    </ToggleButton>
</Stackpanel>
</Grid>

Notice how our toggle button's IsChecked property is bound to our CanExecute property. When we check the control it will update the property state and in turn call the 'RaiseCanExecuteChanged()' method on our TestCommandCanExecuteRC Command. Since our button is bound to the TestCommandCanExecuteRC Command, our button's IsEnabled state will be updated to reflect any property change that may have occurred.

Run the application and notice that the our 'command execute' button is disabled. Our button is disabled because we initialized our '_canExecute' member to false. CanExecute is called on initializition which means the CanExecute state is set initially. When you click on the toggle button you should notice our button state has changed for command execute. You should now be able to click on the command execute button and it should execute the command and pop the message box we specified in code.

Passing a Parameter

Another thing you can do with commands is pass a parameter. You pass a parameter by specifying the Parameter in the control. Look at the example below. In this case our CommandParameter contains the string 'Command Parameter Test'.

<Button command="{Binding TestCommandPassParameterRC}" commandparameter="Command Parameter Test"/>

Create a new MVVM Light Project from the SL4 template and open MainViewModel.cs. By now you know how to setup a Command so lets get to it.

Setup the Command:

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

Setup the function that will be called when our Command is executed, in this case taking a string parm:

// TestCommandPassParameter -
private void TestCommandPassParam(string obj)
{
    MessageBox.Show(obj);
}

Initialize the Command:

TestCommandPassParamRC = new RelayCommand<string>((obj) =>TestCommandPassParam(obj));

Notice in the line above when initializing our Command that this time we specify the type of parameter we will take and pass to our function. We aren't setting up any properties for this example so we just need to fill out the View in MainPage.xaml.

The View

<Grid x:name="LayoutRoot">
    <TextBlock fontsize="36" fontweight="Bold" foreground="Purple" horizontalalignment="Center" text="{Binding Welcome, Mode=TwoWay}" textwrapping="Wrap" verticalalignment="Center"></TextBlock>

    <Button command="{Binding TestCommandPassParameterRC}" commandparameter="Command Parameter Test" content="Show command parameter" margin="45,226,42,12"></Button>
</Grid>

Notice above how our button binds to our 'TestCommandPassParameterRC' Command and passes the CommandParameter as a string. When the Command is executed it will pass in the 'Command Parameter Test' string to our function and call the messsage box as we specified with our parameter (string) as the message. Run the application and click the Button to see it in action.

Closing

In this part we discussed Commands and learned how they are used in MVVM Light. We learned how to Create a Command, Bind a Command to a control, and how to Pass a Parameter using CommandParameter. You should now have the basic knowledge needed to implement your own Commands and Bind them to Controls.

Next in the series: MVVM Light for Silverlight Part 4: EventToCommand Behavior