Andrej Tozon's blog

In the Attic

NAVIGATION - SEARCH

Silverlight TreeView: MVVM and editing [2 – Commanding]

This post is about commanding. In MVVM application context, one way to describe commanding would be to call it a ‘declarative way of connecting Actionable Elements with some Actions by the means of Commands’.

Right… First things first – what’s an ‘Actionable Element’? Actionable elements are all elements (or controls), that can respond to some action from the user by raising an appropriate event. For example: when you click on a button, it raises the Click event. By this definition, all clickable controls are actionable elements. Let’s take a look at the TextBox – is it an actionable control? Of course it is! There are many cases you want for something to happen when you press an enter key when inside the TextBox. And thinking of a ListBox – sometimes it’s its SelectionChanged event you want to respond. Now you get the idea…

So what’s an ‘Action’? Putting it in a well-known terms, it’s simply an event handler. So instead of writing this in Xaml:

<Button Click="Button_Click" />
 
and then implementing the Click event handler in the code behind:
 
private void Button_Click(object sender, RoutedEventArgs e)
{
    // Do stuff
}
 
you would write something like:
 
<Button Command="DoSomeStuff" />
 
and instead of writing the event handler in your Xaml’s code behind, you would write it there where it belongs to. With MVVM application, this place is usually the ViewModel.

And now we get to the ‘Command’. Think of it as a some kind of a delegate to your action – your one and only event handler, which will handle that one command. Many actionable elements can then be assigned this exact command to perform when acted upon.

Commanding is also one of the many things here Silverlight differ from WPF. WPF has a powerful commanding support built in the framework, while on the other hand, there is only a small trace of commanding that can be seen in Silverlight – the ICommand interface… and that’s it! Needless to say, in order to build a competent MVVM solution in Silverlight we need commanding.

One common approach to introduce commanding in Silverlight is by attached behavior. Attached behavior is a way to extend an element by attaching a ‘behavioral’ property to it - you create an attached property with custom logic and attach this property to an element, which is supported by this property.

There are several examples on how to create commanding support in Silverlight around the web, but from what I could gather, the implementation from the SLExtensions project (CodePlex) currently seems to be the most popular one. And that’s the also one going to be used in this series. In fact, the Input folder in this solution project is a copy from the one in the SLExtensions. The SLExtensions Command pattern is not exactly the same as in WPF, but it’s very close and adequate.

To get back to our case and use the new knowledge of commanding, we’ll create two commands – one for adding, the other for deleting our help topics:

public static class Commands
{
    static Commands()
    {
        AddTopic = new Command("AddTopic");
        DeleteTopic = new Command("DeleteTopic");
    }

    public static Command AddTopic { get; private set; }
    public static Command DeleteTopic { get; private set; }
}
 
then add two buttons to our page, pointing to that commands through an attach property, provided with the abovementioned Command pattern:
 
<StackPanel Orientation="Horizontal">
    <Button Content="Add Topic" input:CommandService.Command="AddTopic" />
    <Button Content="Delete Topic" input:CommandService.Command="DeleteTopic" />
</StackPanel>

The last thing we have to do  is create the command event handlers for the actual work. We’ll do that in the ViewModel because that’s where all action is. We’ll keep the logic behind both of commands very simple: AddTopic command will add a topic as the child of the first node in the tree, while DeleteTopic will remove the last child of the same node, if any children present:

private void OnAddTopicExecuted(object sender, ExecutedEventArgs e)
{
    HelpTopics[0].SubTopics.Add(new HelpTopic() { Name = "Custom Topic" });
}

private void OnDeleteTopicExecuted(object sender, ExecutedEventArgs e)
{
    if (HelpTopics[0].SubTopics.Count == 0)
    {
        return;
    }
    HelpTopics[0].SubTopics.RemoveAt(HelpTopics[0].SubTopics.Count - 1);
}

Observing a running application (source code below) shows how User Interface (the TreeView) reacts to changes in the underlying ViewModel, triggered by commands, attached to ‘actionable’ buttons. Still no code in our Page code behind, which is good…

To finish this post, I’ll show another feature of commanding: conditional invocation. You can prevent the command from being called if the criteria for command’s invocation is not met. With the current commanding implementation, we just have return a boolean, indicating whether the criteria for a command is met or not, as a response to a CanExecute event. To check on whether a topic can be deleted or not, we’d use:

private void DeleteTopic_CanExecute(object sender, CanExecuteEventArgs e)
{
    e.CanExecute = HelpTopics[0].SubTopics.Count > 0;
}

In this post I introduced commanding and show a very basic example on how it’s used in a MVVM application.

Next in the series: moving to the TreeView [finally :)]

The source code for this sample is available: