Using Commands in BabySmash

For background, you should read the first post by Scott Hanselman on his BabySmash project. I’ve already written one post on how to to do configuration better. In this post, I’ll cover another aspect of WPF that Microsoft got right: commands.

I’ve written about commands before. In that post, I was describing a way to implement Commands in Windows Forms. They are completely missing in Windows Forms, but in WPF, they got first class treatment.

Why Commands?

In my WinForms article, I didn’t really discuss what Commands were. Oh well. I’ve always told myself to proof read, but I never seem to listen.

Consider an operation like opening a text file. Suppose you were writing a notepad clone. That would be an important operation to support. Notepad has a menu with a menu item that shows the system’s OpenFileDialog, lets you pick a file and open it, display it, etc. Now suppose you wanted to do one better than Notepad and you wanted a right-click menu with a menu item that does the same thing. You’d handle the Click event for your new context menu item, and do the same thing as in your notepad clone’s main menu item. A little later in the dev cycle, you decide you’re going to have a Toolbar with a button that lets you open a file too. Then you decide that your notepad clone is so important that you’re going to have a icon in the system tray with a context menu that lets you open a file from one of the menu items. I could go on and on with, say, keyboard shortcuts and the like, but I think I’ve gone far enough.

What does your code look like now? If you were smart, you’d have one method in your Window class that would handle opening a file and call that method from all the click handlers. If you were really smart, you’d hook up all the Click events you were handling to the same method. But you probably handle each one separately and copy the code each time. That’s what I’d do when I was just starting out.

This is probably fine for a notepad clone; it’s fairly straightforward, there’s one window that doesn’t do much. If you started out with the write once/paste anywhere coding style, you could refactor to a more streamlined approach like the other two above. But consider how Visual Studio would look like if it took this approach. A operation can be called from just about anywhere in VS. If it were coded like my theoretical notepad clone, the main window must be millions of lines long: there are tons of operations in VS. Of course, VS is not coded like that. They use commands.

What if we wanted to make our open operation in the notepad clone a little more permanent? We’d probably want to take the code and move it into it’s own class that could be re-used across our whole app, independent of the window. You’ve essentially just made a command: separated the logic of the operation from the UI that invokes that operation. There would likely be more than one operation too, and if we did that to every operation, we’d probably see a lot of duplication in those classes. Duplication that can be removed by formalizing the reoccurring pattern. This idea really takes off when it’s built right in to your UI framework; the controls you use could know about commands, there could be a set of built-in commands that are common enough that they are worth implementing by the framework. Fortunately, Microsoft has done with WPF.

For complete background on commands in WPF, you should check out Jelle Druyts’s article. He explains it really well, and there’s basically nothing I can add that doesn’t repeat what Jelle already says.

Instead what I’ll do is show you what I did in BabySmash to reduce some of the code that Scott wrote, and that you’d have to write in your apps, and let the system to it for us. I’ll explain just enough about how commands work in WPF, but you should really read Jelle’s article. It’s ok, I’ll wait for you.

BabySmash lets a baby, or anyone, repeatedly mash the keyboard which makes fun things happen. That’s the main part of the app, but there are some ancillary things that all apps need, like settings and setting those settings, which I’ve covered already. We also need a way to open the dialog to set the settings. To open the options window, one has to press Ctrl-Shift-Alt-O. Scott sniffs for that in the "main loop" of his app, the KeyUp event handler. Perfectly fine really, there’s only one operation right now, but he may want to add more, then that KeyUp handler method will started getting hairy….er. Also, I’m a firm believer in methods doing one thing. Right now the KeyUp handler is doing many things.

private void Window_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
    //HACK: Why did I find the Windows Forms modifier keys classes to be so much more accurate?
    bool Alt = (System.Windows.Forms.Control.ModifierKeys & WinForms.Keys.Alt) != 0;
    bool Control = (System.Windows.Forms.Control.ModifierKeys & WinForms.Keys.Control) != 0;
    bool Shift = (System.Windows.Forms.Control.ModifierKeys & WinForms.Keys.Shift) != 0;


    if (Alt && Control && Shift && e.Key == Key.O)
    {
        e.Handled = true;
        Options o = new Options();
        o.ShowDialog();
        return;
    }

    numberOfShapes++;
    if (numberOfShapes > Properties.Settings.Default.ClearAfter)
    {
        numberOfShapes = 1;
        MainCanvas.Children.Clear();
    }

    PlayLaughter();
    ...
}

So let’s separate out the Options window opening code. To do that, as Jelle explains, we need to declare a command binding. We could do that in code, but let’s do it in XAML.

<Window x:Class="BabySmash.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Baby Smash by Scott Hanselman - http://www.hanselman.com/babysmash"
        Height="386" Width="601"  WindowStyle="None"
         Topmost="True" Activated="Window_Activated" Closing="Window_Closing"    
        
    AccessKeyManager.AccessKeyPressed="Window_AccessKeyPressed"
       KeyUp="Window_KeyUp" KeyDown="Window_KeyDown"
       Loaded="Window_Loaded"
        >
    <Window.CommandBindings>
        <CommandBinding Command="Properties" Executed="Properties_Executed"/>
    </Window.CommandBindings>
    <Grid>
        <Canvas x:Name="MainCanvas">
            
        </Canvas>
    </Grid>
</Window>

Here’s the Window1.xaml from BabySmash with a CommandBinding declared. I’m using the built-in command, ApplicationCommands.Properties. Technically, not semantically correct, but close enough for our purposes. The CommandBinding is basically saying when someone invokes the Properties command for this window, handle it in the Properties_Executed handler, shown below.

private void Properties_Executed(object sender, ExecutedRoutedEventArgs e)
{
   Options o = new Options();
   o.ShowDialog();
}

We’re almost ready to delete some of Scott’s code. Now we have to hook up a way to invoke the command. If there were buttons or menu items in BabySmash, we could just set the Command property on them and WPF takes care of it all. It doesn’t, so we have to do a little more. We have to create an InputBinding for the Ctrl-Shift+Alt+O shortcut key, known in WPF as an InputGesture.

<Window>
    <Window.CommandBindings>
        <CommandBinding Command="Properties" Executed="Properties_Executed"/>
    </Window.CommandBindings>
    <Window.InputBindings>
        <KeyBinding Gesture="CTRL+ALT+SHIFT+O" 
                    Command="{x:Static ApplicationCommands.Properties}" />
    </Window.InputBindings>
    <Grid>
        <Canvas x:Name="MainCanvas">
            
        </Canvas>
    </Grid>
</Window>

Note the two ways in XAML to declare the command. The first one, in the CommandBinding element is allowed because it’s a built-in command. The second way will work for your custom commands as well. That’s it.

Now the KeyUp handler can be simplified by deleting code; as Scott pointed out, always a good thing.

private void Window_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
    numberOfShapes++;
    if (numberOfShapes > clearAfter)
    {
        numberOfShapes = 1;
        MainCanvas.Children.Clear();
    }

    PlayLaughter();
    ...
}

I’ll leave it as an exercise for you following at home to add the close command and an InputBinding for ALT-F4. I didn’t test thoroughly but this can handle the problem that Scott noticed with multiple monitors.

StaticResource does not mean static

My post about BabySmash got hanselmanned. There are some questions in the comments on that post that are worth addressing in another couple posts, so here’s the first. For background, we have Scott’s follow up post, describing how he changed the code because of my post.

In Scott’s post, Configuration with DataBinding, he wrote the following:

Next, we tell the Grid that’s laying out the controls that we have some static data we’ll be using and we call it "settings" because that’s the class name.

<Grid DataContext="{StaticResource settings}">

There are a few misunderstandings in this statement that I’d like to clarify, since this is a learning experience and all.

There are two big WPF concepts here, DataContext and StaticResource. I’ll tackle StaticResource here. Consider the XAML below:

   1: <Window x:Class="WpfApplication1.Window1"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     xmlns:System="clr-namespace:System;assembly=mscorlib"
   5:     SizeToContent="WidthAndHeight">
   6:     <Window.Resources>
   7:         <System:String x:Key="s">Hello</System:String>
   8:         <System:String x:Key="i">42</System:String>
   9:     </Window.Resources>
  10:     <StackPanel>
  11:         <TextBlock Text="{StaticResource s}" />
  12:         <TextBlock Text="{DynamicResource i}" />
  13:     </StackPanel>
  14: </Window>

This is the world’s tiniest window. I have two TextBlocks – think of TextBlock as a simple label, for now – one below the other, whose text is set to some string values. I’ve declared the strings in the window’s ResourceDictionary, through the Window.Resources property. The Resources property is declared on FrameworkElement, from which all controls in WPF inherit, so it’s on every WPF control. The StackPanel has a ResourceDictionary, the two TextBlock’s do, the App object (not shown) does, and the system does too.

A ResourceDictionary is basically a giant hashtable. You can store any .NET object you want, like I did above. You can do this from code as well, which perhaps may be more appropriate (since XAML tends to obscure things; remember: anything in XAML can be done in [way more verbose] code):

   1: public class Window2 : Window
   2: {
   3:   public Window2()
   4:   {
   5:      //declaring the same resources in code
   6:      this.Resources.Add("s", "Hello");
   7:      this.Resources.Add("i", "42");
   8:   }
   9: }

I have two strings sitting in a ResourceDictionary. Now, I want to access them. Let’s do that in code first. In the code below, I create my StackPanel, add my TextBlocks to it, and set the values on them. Here’s the not-quite-equivalent code version of the XAML declared at the beginning.

   1: public Window2()
   2: {
   3:    //declaring the same resources in code
   4:    this.Resources.Add("s", "Hello");
   5:    this.Resources.Add("i", "42");
   6:  
   7:    StackPanel stackPanel = new StackPanel();
   8:    //setting the textblocks' text property to resources 
   9:    TextBlock textBlock1 = new TextBlock();
  10:    textBlock1.Text = (string) this.Resources["s"];
  11:    
  12:    TextBlock textBlock2 = new TextBlock();
  13:    textBlock2.Text = (string) this.Resources["i"];
  14:  
  15:    stackPanel.Children.Add(textBlock1);
  16:    stackPanel.Children.Add(textBlock2);
  17:  
  18:    this.SizeToContent = System.Windows.SizeToContent.WidthAndHeight;
  19:    this.Content = stackPanel;
  20: }

I say not quite equivalent because the XAML is doing something slightly different. In the code version, I access the resource directly. In XAML, I’m telling WPF that the values I want for the Text properties are resources, one static and one dynamic (which I’ll get to in a moment). WPF will then move up the control hierarchy (I’m not sure exactly, but I think it moves up the logical tree) and check each ResourceDictionary for the key given. So it’ll check the StackPanel’s resources, then the Window’s. If it wasn’t in the Window’s resources, it would move up to the App resources, and finally to System resources. Resources are really important in WPF; it is where things like Brushes, Colours, Styles and Templates are put. If you were making a skinnable app, you’d make heavy use of resources.

Now, let’s clear up what the StaticResource does. Here’s the relevant XAML again:

<TextBlock Text="{StaticResource s}" />
<TextBlock Text="{DynamicResource i}" />

The curly braces means this is a MarkupExtension, a XAML-only concept that allows us as developers to be slightly more expressive than plain old XML allows. The meaning of static in this case may be clearer when juxtaposed with it’s brother, they DynamicResource. There is a class behind these two, StaticResourceExtension and DynamicResourceExtension. You could try writing the equivalent code; I did, and it didn’t work, but in the docs there is the ominous warning that this is used by the XAML subsystem and shouldn’t be called by humans.

The difference between StaticResource and DynamicResource is how they are accessed by WPF. The semantics of StaticResource are "just read this value once, and don’t check for changes." It’s static as in not moving, not as it is in C#. Note that the two objects in the window’s resources are plain old string instances.  StaticResources are good for things that don’t change, like Brushes or Styles, or read-only data. It’s unfortunate from a learning perspective that the data in BabySmash was static in the C# sense as well, but it’s just a coincidence, honest.

DynamicResource on the other hand is a little more intensive for WPF, because it will track changes to the ResourceDictionary. So if the value of a DynamicResource changes, WPF knows about it and updates the control accordingly. This is good for data that changes, obviously.

Let’s expand the XAML just a bit, and add a button with a click handler. In the click handler, let’s update the value keyed with "i". Run the code, click the button and watch as 42 becomes world. And you don’t have to write anything to make this happen.

<StackPanel>
    <TextBlock Text="{StaticResource s}" />
    <TextBlock Text="{DynamicResource i}" />
    <Button Click="Button_Click">Click me</Button>
</StackPanel>
 
private void Button_Click(object sender, RoutedEventArgs e)
{
    this.Resources["i"] = "world";
}
 

Redoing the Options Dialog in BabySmash

Scott Hanselman introduced us to BabySmash today. It’s an app for his kids that he developed using his arcane Win32 knowledge in a WPF app. He did it on purpose, mind you, to teach himself WPF, with us watching.

I think this is a fantastic idea. When I was writing the AutoComplete TextBox series, I thought it would be a cool idea for all the major WPF book authors (Adam Nathan, Chris Sells & Ian Griffiths, Charles Petzold and Chris Anderson) to write their implementations of the same problem. They’re all very good at explaining, they’d all come up with different solutions and we could all figure out the best way to do things in WPF, as Scott alludes to in his post on BabySmash.

I’ve taken a look at the code and, boy, it needs work. I saw immediately something I’ve experienced pain with before, which I’ll talk about in this post: custom settings. In .NET 2.0, one of the cool The default Settings.settings file.unsung heroes is the settings code in System.Configuration. Note that it’s not tied to WPF or WinForms. With it, you’re able to have user- or app-scoped settings. They can be local or roamable. The framework takes care of storage, although it’s extensible. Visual Studio assists with code-gen so you can access your settings with code.

By default, VS will create a Settings class that inherits from ApplicationSettingsBase in the YourProjectNamespace.Properties namespace. The settings you create in the Settings designer get properties generated for them. The Settings class also has a static instance accessed through the Default property. Scott actually created this file, but then didn’t use it. I haven’t used ClickOnce, but I just can’t see Microsoft not supporting the settings file automagically in ClickOnce.

Pictured below is BabySmash’s settings with Scott’s intended properties filled in.

The settings Scott already used in BabySmash filled in the settings file

So, like I said, this is independent of UI framework. How do we use it in WPF? Databinding! By far the best thing of WPF, even though you have to put some time in to learn it.

Before I show the code to databind to the application settings, allow me to show you the XAML for the Options page in BabySmash.

<Window x:Class="BabySmash.Options"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Baby Smash! - Options" Unloaded="Window_Unloaded" Loaded="Window_Loaded" Height="188" Width="268" ShowInTaskbar="False" Topmost="True" WindowStartupLocation="CenterScreen" WindowStyle="ThreeDBorderWindow" ResizeMode="NoResize">
    <Grid>
        <Button Height="23" Name="OK" VerticalAlignment="Bottom" Click="OK_Click" IsDefault="True" Margin="64,0,102,9">OK</Button>
        <Button Height="23" Margin="0,0,8,9" Name="Cancel" VerticalAlignment="Bottom" IsCancel="True" HorizontalAlignment="Right" Width="80" Click="Cancel_Click">Cancel</Button>
        <Label Height="28" Margin="14,19,0,0" Name="lblClearAfter" VerticalAlignment="Top" HorizontalAlignment="Left" Width="120">Clear After x Shapes</Label>
        <TextBox Height="23" Margin="0,19,8,0" Name="txtClearAfter" VerticalAlignment="Top" HorizontalAlignment="Right" Width="101"></TextBox>
        <CheckBox Margin="0,81,0,0" Name="chkForceUppercase" Height="16" HorizontalAlignment="Right" VerticalAlignment="Top" Width="109" >Force Uppercase</CheckBox>
        <ComboBox Margin="0,48,8,0" Name="cmbSound" Height="23" HorizontalAlignment="Right" VerticalAlignment="Top" Width="101" IsDropDownOpen="False">
            <ComboBoxItem>None</ComboBoxItem>
            <ComboBoxItem>Speech</ComboBoxItem>
            <ComboBoxItem>Laughter</ComboBoxItem>
        </ComboBox>
        <Label Height="28" Margin="14,43,112,0" Name="label1" VerticalAlignment="Top">Sounds</Label>
    </Grid>
</Window>

If you know XAML and how the WPF grid works, then you know that this is really bad code. This is probably the most egregious thing about WPF, IMO: the visual designer. Scott didn’t write this code. Visual Studio did.

Petzold has a great transcript/paper of a talk he gave to a New York user group in 2005 titled, Does Visual Studio Rot the Mind? In it he talks about the evolution of visual programming and Visual Studio. It’s written in 2005, before WPF even got its name, but while he was writing his book, Applications = Code + Markup. But the points he raises are still valid. WPF is, by default, laid out without reference to pixels. The intention of its designers was that with WPF, you say what you want, the WPF figures out how to make it so. Most of the new frameworks from Microsoft have that in their design: "tell me what, I’ll figure out how."

In WPF’s case, it’s completely undermined by the visual designer in Visual Studio. Note above the code snippet from Scott’s Options page: see all those Margin attributes? That’s like hard-coding the same string value in more than one place. This is a dialog box, but humour me. Suppose we allowed this dialog to be resized by the user. What would happen? Chaos.

 The visual chaos of visual studio defaults.

This is what Visual Studio gives you out of the box. Shameful. And if you want to use databinding, forget it, you have to write the XAML by hand. I am dimly aware of Expression Blend; I’ve used it a few times and I think I remember it being a little smarter than Visual Studio. I think that shows how Microsoft is a little out of touch with developers outside of Microsoft. In theory, I like the idea that developers can work on the app doing something, while designers work on the app’s appearance. Really good idea, in theory. In my experience, the developer is the designer the majority of the time. In this scenario, Visual Studio needs a lot more work.

Anyway, let’s stop ranting. I also think it’s a developer’s responsibility to learn either how technology is used if it’s well-established, in the case, of, say, PHP or ASP.NET; or how its designers intended it to be used in the case of WPF. That’s what I’ve done, and what I’m still doing now. So let’s make an Options window that binds to the app settings. Scott’s was laid out, as he intended it, as the following:

The BabySmash Options dialog

There are plenty of ways to do this with the default panel types in WPF. I’ll use the Grid since it’s the most powerful, the default choice and hence the most popular. I’ll preserve as much of what Scott had, and try to make it pixel perfect.

OK, I’m back. Did you miss me? Here’s what I have:

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1.Properties"
        xmlns:l="clr-namespace:WpfApplication1"
        Title="Baby Smash! - Options" 
        Height="188" Width="268"
        ShowInTaskbar="False" 
        Topmost="True" 
        WindowStartupLocation="CenterScreen" 
        WindowStyle="ThreeDBorderWindow" 
        ResizeMode="NoResize">
    <Window.Resources>
        <local:Settings x:Key="settings" />
    </Window.Resources>
    <Grid DataContext="{StaticResource settings}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Label Height="23" Margin="10,20,0,0" Grid.ColumnSpan="2">Clear after x Shape</Label>
        <TextBox Text="{Binding Path=Default.ClearAfter}" 
                 Height="23"  Grid.Column="1"
                 Margin="15,20,0,0"/>
        <Label Height="23" Grid.Row="1" Margin="10">Sounds</Label>
        <ComboBox Grid.Column="1" Grid.Row="1" Height="23" Margin="15,0,0,0">
            <ComboBoxItem >None</ComboBoxItem>
            <ComboBoxItem >Laughter</ComboBoxItem>
            <ComboBoxItem >Speech</ComboBoxItem>
        </ComboBox>
        <CheckBox Grid.Row="2" Grid.Column="1" Margin="15,0,0,0"
                  IsChecked="{Binding Path=Default.ForceUppercase,Mode=TwoWay}" >
            Force Uppercase
        </CheckBox>
        <StackPanel Orientation="Horizontal" Grid.Row="3" Grid.ColumnSpan="2" 
                    HorizontalAlignment="Right">
            <Button Name="okButton" IsDefault="True" 
                    Margin="0,7,10,7" 
                    Padding="30,0,30,0" Click="okButton_Click">OK</Button>
            <Button IsCancel="True" 
                    Margin="5,7,7,7" 
                    Padding="15,0,15,0">Cancel</Button>
        </StackPanel>
    </Grid>
</Window>

It looks more verbose for sure, but I think that’s more because of editing by hand and using the ENTER key. Let’s pull out unnecessary stuff and show the code that binds to the application settings

<Window x:Class="WpfApplication1.Window1"
        xmlns:local="clr-namespace:WpfApplication1.Properties"
        xmlns:l="clr-namespace:WpfApplication1"
        >
    <Window.Resources>
        <local:Settings x:Key="settings" />
    </Window.Resources>
    <Grid DataContext="{StaticResource settings}">        
        <TextBox Text="{Binding Path=Default.ClearAfter}" />
        <CheckBox IsChecked="{Binding Path=Default.ForceUppercase}" >
            Force Uppercase
        </CheckBox>
        <StackPanel >
            <Button Name="okButton" IsDefault="True" 
                    Margin="0,7,10,7" 
                    Padding="30,0,30,0" Click="okButton_Click">OK</Button>
            ...
        </StackPanel>
    </Grid>
</Window>

There are some concepts you’ll see over and over again WPF: the use of ResourceDictionaries (Window.Resources in the XAML), DataContext, and DataBindings. I won’t explain all of it in detail (this post is long as is), but I’ll briefly explain it and bold terms that you can search the internets for more info.

Most of the XAML should be familiar even if you’ve never seen it before. It’s fairly close to ASP.NET code, if memory serves, and the XML hierarchy is a good fit for a model that represents a window as a nested tree of controls. The Windows.Resources element adds a Settings object to the window’s ResourceDictionary. All resource dictionary items must have a key to refer to. We set the DataContext on the Grid to the settings object declared in the resources. It’s a StaticResource which means that WPF loads it once and stops listening to updates to that resource. The DataContext is essentially associating the Settings object with the Grid. The  Binding on the TextBox’s Text property is BindingExpression whose Path points to the Default.ClearAfter property of the Settings object. That’s a little advanced, but hey, it’s "real world." And that’s all you have to do to get the settings to show up in the right controls. Notice there is no procedural code.

There’s one more thing to talk about before I quit. The Settings object’s properties change when you change the values in the controls (set the TextBox to 32, and ClearAfter is set to 32), but we have to tell the Settings object that we want to keep those values. We do that in okButton’s handler:

private void okButton_Click(object sender, RoutedEventArgs e)
{
   Properties.Settings.Default.Save();
   this.Close();
}

Too easy, eh?

There are some caveats because I didn’t test thoroughly: databinding by default updates the source after focus changes so if you set the TextBox to 32, then click OK, it may not update the property properly as you’d expect. I explicitly left the third property in settings to be set by you if you want to take up the challenge. I added the settings in BabySmash but they weren’t showing up properly. I don’t know why and I didn’t pursue.

So there you have it. I didn’t show Scott’s Option dialog code, but I’ve significantly reduced it. My Options Dialog window XAML code may be a little longer but I get some layout benefits by using the Grid to its potential. Of course, you may do something different, and it may be better, but that’s the whole point of the Scott’s app. There are some treats in the solution below. I got tired of writing this post before I covered everything that I noticed. I’m going to play video games now.

Using the Command Pattern in Windows Forms clients

I’ve been doing a lot of research with the Command pattern lately at work. Here’s what I found: You’re doing yourself a disservice – and your team – if you don’t play the hell outta this thing!

It’s a very powerful design for non-trivial Windows Forms clients. What’s non-trivial? Anything that uses a menu, toolbar or context menu to show perform the same action. In fact it’s so useful and so powerful that I’m a little disappointed that Microsoft didn’t provide something like it in the framework itself. They’ve provided something in Avalon WPF, but I haven’t had the chance to play with it. I know they use it: Visual Studio and Office take advantage of it. (For example, think of how many ways you can copy and paste text.)

What are some of the advantages?

  • Automation – how easy is it to automate tasks in Visual Studio with a macro? Or reassign a keyboard shortcut? Enough said.
  • Completely decouples the UI from the business objects. It’s easy to say this but really hard to do it, especially if deadlines are tight. With commands, you can keep the UI and throw away the business objects or vice versa.
  • Easily allows plugins or addins. Suppose you have a client with a unique look that you want to control, but you want to offer the ability to extend or introduce functionality to third parties. Commands allow that. It’s how Visual Studio Add-ins do it.

There are disadvantages, of course – every design has drawbacks:

  • It complicates the application design. Every pattern complicates application design; they’re used because the benefits outweigh the cost. In fact, they should only be used when the benefits outweigh the costs.
  • Using commands complicate your controls and forms. Suppose you have a button that will be used to execute a command. Do you subclass Button so that it contains a Command and override OnClick? Do you use a normal Button and handle the Click event in the form? Change Button with MenuItem. Repeat questions.
  • Debugging is a little harder. There are features in .NET 2.0 to mitigate this one.

So what does a Command look like? Well, that’s largely up to you. The bare minimum would be one method that would allow you to perform the action associated with a Command:

public interface ICommand

{

void Execute();

}

All of your concrete commands would implement this interface and when the button or menu is clicked, call command.Execute(). Easy, eh? There is a whole lot more you can do with the shared interface, however. In fact, there is a lot of common code that you can take advantage of, which is why I prefer an abstract class, like so:

public abstract class Command

{

public string Key { get; protected set; }

public string DisplayName { get; protected set; }

 

public bool Enabled { get; }

 

public abstract void Execute();

}

All the properties would have an implementation, I leave it out because I’m only concerned with API right now. We still have that abstract Execute() method, but now we have a few properties that deserve some explanation. To further separate the UI from the business logic, if the text that the user sees is associated with the command rather than the UI, then you can easily replace the commands without modifying the UI at all. This is extremely powerful when you start dealing with collections of commands that can all be handled in the same way. So that explains DisplayName.

The Enabled property is fairly obvious: there are times when it would either be impossible or just plain wrong to perform an action; in those cases, you want to disable the UI so that the action cannot be performed. I’ll come back to the Enabled property in a second.

The Key property is for when Commands are grouped together in a collection. It makes sense to store most of your commands globally with the main form in a list or map. We’ll need a way to uniquely identify them so that we can retrieve them later. That’s what the Key property is for. Go to Tools -> Options in Visual Studio, select Keyboard. There you’ll see the keys for the commands in Visual Studio, no pun intended.

Now, by itself, the above Command is very powerful. However, we’re not done. Combine the above with Data Binding in Window Forms and you have to write almost no code at all. Data Binding is a very powerful technology, which you’ll know about if you’re one of the millions of ASP.NET developers out there. In .NET 2.0, Windows Forms apps got the same treatment. I can’t cover data binding in detail in this post, so I’ll just assume you know about it. To really take advantage of Data Binding I have to modify my Command class slightly:

public abstract class Command : INotifyPropertyChanged

{

bool enabled;

string key, displayName;

 

public event PropertyChangedEventHandler PropertyChanged;

 

public string Key

{

get { return key; }

protected set { key = value; }

}

 

public string DisplayName

{

get { return displayName; }

protected set

{

if (displayName != value)

{

displayName = value;

OnPropertyChanged(new PropertyChangedEventArgs(“DisplayName”));

}

}

}

 

public bool Enabled

{

get { return enabled; }

set

{

if (enabled != value)

{

enabled = value;

OnPropertyChanged(new PropertyChangedEventArgs(“Enabled”));

}

}

}

 

public abstract void Execute();

 

protected void OnPropertyChanged(PropertyChangedEventArgs e)

{

PropertyChangedEventHandler handler = PropertyChanged;

if (handler != null)

handler(this, e);

}

}

OK, I gave you the whole implementation. You’ll see that my Command class now implements the INotifyPropertyChanged interface. This allows the data binding code to update the control that has bound to the data when the data changes. You’ll note that DisplayName and Enabled will raise the PropertyChanged event. Therefore you can create a Button, hook it up to a Command with a minimum of code and let the power of data binding deal with turning the command on and off:

Button button = new Button();

Command command = new ArbitraryCommand(“My Data”);

button.DataBindings.Add(“Text”, command, “DisplayName”);

button.DataBindings.Add(“Enabled”, command, “Enabled”);

button.Click += delegate { command.Execute(); };

This technique is very powerful when your business objects change on their own without user interaction.

There are few things you have to note. The DisplayName property will have to be internationalized if your app is interested in the rest of the world, which will make the class more complex. Also, the Command pattern kind of falls down when you need to pass data to the command. You lose the polymorphism of the Command class when you have to either know the specific concrete type or what data must be passed to a particular command.

Still, if you are doing serious Windows Forms apps, you should consider the Command pattern.

Technorati tags: , patterns

Now playing: Santana – Just Feel Better (Feat. Steven Tyler Of Aerosmith)