Chapter 4. Practical WPF

In This Chapter

  • Commanding attention

  • Getting your ViewModel on

Even though WPF still supports the direct event handler wire up (for example, through the OnClick event), WPF introduces a much better mechanism for responding to user events. It significantly reduces the amount of code you have to write and adds testability to your application. Traditional event handling is all contained in the code-behind for your form, which is extremely difficult to test in an automated fashion.

Software patterns have been around for a long time, first brought to the forefront by the classic tome Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, and John Vissides — commonly referred to as the "Gang of Four." Software has evolved and many new patterns have been developed over the years. One of the most effective user interface patterns developed for WPF is the Model-View-View Model pattern (commonly referred to as ViewModel). Using the ViewModel pattern in your WPF applications will improve software reuse, testability, readability, maintainability, and most of the other "ilities" as well.

Commanding Attention

The Command Pattern has been around since, well, forever, and you most likely use it every day. Copy and Paste commands are example implementations of the pattern built into Windows and most Windows applications. WPF provides a significant number of built-in commands and also allows for completely customized commands!

Traditional handling of user events (and still supported in WPF) is through an event handler. When the button on the Window is clicked, the code in the event handler (which has to be in the code-behind file) will execute. By placing this code in the code-behind event handler, the business logic is now mixed with the user interface code, mixing concerns. To be fair, nothing in the framework makes one put the code in the code-behind; it just seems to always end up there.

This gets compounded when additional UIElements are added to the Window that needs to execute the same code. The common fix for this situation is to refactor the code in the original event handler out into a separate method and have the event handlers for the related UIElements call the new method. The new method can even be moved into the Business Layer, separating concerns and allowing for testability.

The other issue is one of user experience. Often, menus and buttons need to be actively enabled or disabled based on the condition of the data (or some other condition/user action) in the Window. If the user has the option, they tend to click "active" items repeatedly, wondering why nothing is happening. They are, after all, trained at birth to find holes in your application.

The command pattern as implemented in WPF cleanly and easily resolves both issues.

ICommand

ICommand (which is the base interface for all commands discussed here) defines two event handlers and one event. See Listing 4-1.

Example 4-1. ICommand Interface

bool CanExecute(object parameter);
void Execute(object parameter);
event EventHandler CanExecuteChanged

Perhaps the most powerful feature of WPF commands is the capability to determine at runtime if the controls they are bound to are able to execute (see the next section for a detailed discussion). CanExecute is run by the CommandManager whenever Focus changes, the PropertyChanged or CollectionChanged events are raised, or on demand through code. If the event handler returns false, all UIElements bound to that command are disabled.

The Execute event handler contains the code that gets executed when the user action is processed or the command is executed through code.

The CanExecuteChanged event provides a mechanism to tie into the INotifyCollectionChanged and INotifyPropertyChanged event handlers to determine when CanExecute needs to be requeried.

Routed commands

The ICommand interface doesn't provide the entire goodness of commands in WPF. The RoutedCommand class (and its first descendant, the RoutedUICommand) take advantage of Event Routing to provide additional power.

The CanExecute event handler raises the PreviewCanExecute event and the Execute event handler raises the PreviewExecuted event. These events are raised just prior to the CanExecute and Execute handlers, and bubble up the element tree until an element with the correct Command Binding is located. This is useful for allowing control of commands at a higher level while the fine-grained elements still control the CanExecute and the Execute event handlers.

Routed Commands also expose a collection of InputGestures — keystrokes or other gestures that will fire the Execute event handler. This allows assigning hot key combinations to the commands, such as Control+S for saving (as in most Windows applications).

Built-in commands

WPF provides a number of built-in commands that you can use with very little (sometimes no) code. The most common set used by line of business developers is wrapped up in the ApplicationCommands Library. The advantage of using the built-in commands is that all the plumbing is taken care of for you. For example, the CanExecute and Execute event handlers are already implemented. All you have to do is bind them to UIElements through XAML.

Note

The full list of built-in commands is available online at http://msdn.microsoft.com/en-us/library/system.windows.input.aspx.

The sample shown in Listing 4-2 and Figure 4-1 uses the ApplicationsCommand.Copy and ApplicationsCommand.Paste commands to facilitate clipboard manipulation in your application. When the UIElement with focus supports the clipboard Paste action and there is data in the clipboard that is supportable by the element with focus, any elements bound to the Paste command are enabled. When the UIElement with focus supports the clipboard Copy action and there are items selected that can be copied to the clipboard, then any elements bound to the Copy command are enabled. As a side note, WPF allows you to abbreviate the built-in commands by dropping the container name (ApplicationCommands), so Copy and Paste are legitimate abbreviations for the command bindings ApplicationCommands.Copy and ApplicationCommands.Paste. For readability, I prefer to fully qualify the names.

Note

The full code for the Command samples is in the project Chapter4Commands and Chapter4CommandsTests in the Chapter4 Solution.

Example 4-2. Built-in Commands in XAML

<Menu Grid.Row="0" Grid.Column="0" HorizontalAlignment="Left"
   Name="menu1">
    <MenuItem Command="ApplicationCommands.Copy"/>
    <MenuItem Command="ApplicationCommands.Paste"/>
</Menu>
<TextBox Grid.Row="1" Grid.Column="0"
   HorizontalAlignment="Stretch"/>
<TextBox Grid.Row="2" Grid.Column="0"
   HorizontalAlignment="Stretch"/>

Figures 4-1 through 4-3 show the Window produced by the XAML in Listing 4-2 in different states. When there is text selected in a text box, the Copy menu is enabled. When there is data in the clipboard that can be pasted into a text box, the Paste menu becomes enabled. This is all done without a single line of code!

Built-in commands (with empty clipboard and no selections).

Figure 4-1. Built-in commands (with empty clipboard and no selections).

Built-in commands (with empty clipboard and text selection).

Figure 4-2. Built-in commands (with empty clipboard and text selection).

Built-in commands (with clipboard data and no text selection).

Figure 4-3. Built-in commands (with clipboard data and no text selection).

Focus!

I know the question you're dying to ask: If the user clicks on a menu item, doesn't that menu item then have focus? The answer is a confusing "No!" That's because menus in WPF work a little bit of magic to determine what UIElement has focus just before a menu item is clicked.

Unfortunately, this doesn't apply to standard buttons and other command bindable controls. Even though the menu items in Figure 4-4 are enabled, the buttons are not. There are two fixes for this problem. The first is by binding the CommandTarget property in addition to the command to the UIElement. This is a single element solution, though. To resolve the issue for all UIElements, the FocusManager.IsSharedScope property needs to be set to True in the parent container.

Built-in controls with buttons.

Figure 4-4. Built-in controls with buttons.

Custom commands

Creating a custom command requires either instantiation of a new Routed[UI]Command or coding a new command based on the ICommand interface. Well, okay, you are correct — there are other methods as well. The two most popular are what I discuss here.

Custom routed UI commands

Creating a new RoutedUICommand is a simple instantiation, as the code in Listing 4-3 shows.

Example 4-3. Creating a Custom RoutedUICommand

public static RoutedUICommand SaveCommand =
   new RoutedUICommand("Save","SaveCommand",
   typeof(UIElement) );

The first parameter in the constructor populates the Text property, the second parameter is the name used in serialization of the command (I usually append Command to the text from the first parameter), and the last parameter is the UIParent. (In this example, the code states any UIElement can be the parent.) There is a fourth parameter in another Constructor (not shown here) that is a list of InputGestures.

Custom RoutedUICommands are usually created as static variables so there is only once instance (and it makes binding simpler). Yes, it's still in the code-behind file, so we don't yet have Separation of Concerns, but we're getting there!

Command bindings

Unlike the built-in commands (which are part of the framework and automatically wired into the CommandManager and the binding system), custom commands are not. Three changes need to be made in the XAML to support custom commands:

  • Add the namespace for the command to the namespace declaration.

  • Change the command assignment to a binding expression.

  • Add the command to the bindings collection of the container.

As Chapter 1 explains, you can add custom namespace declarations to the Window to allow XAML access to custom classes and namespaces. The namespace for the custom command (which is the same namespace as the Window if the command is a static variable in the code-behind) needs to be added to the Window tag. Listing 4-4 shows an example namespace declaration. The bolded text is what has changed from the default namespace declarations that are in the standard WPF Window.

Example 4-4. Updated XAML for Custom RoutedUICommand

<Window x:Class="Chapter4.Commands.CommandBindingSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/
        presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Commands="clr-namespace:Chapter4.Commands"
        Title="Command Binding" Height="122" Width="261">

After the namespace is brought into the Window, the command must be inserted into the Window.CommandBindings collection. Three main properties need to be set and are shown in Listing 4-5:

  • Command: The binding to the command object

  • CanExecute: Event handler for testing execution status

  • Executed: Event handler for the execution of the command

With built-in commands, a simple string assigned the command to the UIElement. With custom commands, you have to use a binding expression (as discussed in Chapter 3). The format for a static command binding is

{x:Static NamespaceReference:Class.CommandVariableName}.

The NamespaceReference is the nickname assigned in the Window tag. Interestingly, the CanExecute and Executed properties are set to the name of the methods — no funky binding required!

Example 4-5. Window CommandBindings XAML

<Window.CommandBindings>
  <CommandBinding Command="{x:Static
   Commands:CommandBindingSample.SaveCommand}"
   CanExecute="Save_CanExecute"
   Executed="Save_Executed"/>
</Window.CommandBindings>

The Command property of the CommandBinding and UIElements use the same binding expressions as shown in Listing 4-6. When a UIElement has a command bound to it, the framework looks for the first match in the CommandBindings section up the element tree. When one is located, the UIElement uses the assigned event handlers CanExecute and Execute.

Example 4-6. Command Assignment to MenuItem and Button

<MenuItem Command="{x:Static
   Commands:CommandBindingSample.SaveCommand}"/>
<Button Command="{x:Static
   Commands:CommandBindingSample.SaveCommand}"
   Content="{Binding RelativeSource={RelativeSource
   Mode=Self}, Path=Command.Text}"/>

The CanExecute event handler for a Routed[UI]Command uses the CanExecuteRoutedEventArgs instead of returning True or False. Setting e.CanExecute to True (can run) or False (cannot run) will enable or disable the command (and any associated UIElements).

If the command is enabled, the Executed event handler gets executed when the UIElement triggers the command (for example, when a button is clicked).

Command parameters

The CanExecuteRoutedEventArgs and ExecutedRoutedEventArgs contain a Parameter property that provides a mechanism for passing objects from the Window into the CanExecute and Executed event handlers. For the example in Figure 4-5, the text of the TextBox is being passed as the parameter. The CanExecute property of the CanExecuteRoutedEventArgs in the CanExecute event handler is set to False if the string is empty or null, and the Executed event handler displays it back to the user in a message box. Okay, not a realistic example, but it's a demo!

Listings 4-7 and 4-8 show passing a parameter into the command through XAML and then using that parameter in the C# implementation of the events.

Example 4-7. Updated XAML to Include Command Parameter

<Button Command="{x:Static
   Commands:CommandBindingSample.SaveCommand}"
   CommandParameter="{Binding ElementName=txtField,
   Path=Text}"
   Content="{Binding RelativeSource={RelativeSource
   Mode=Self}, Path=Command.Text}"/>

Example 4-8. Updated C# to Display Parameter to User

private void Save_CanExecute(object sender,
   CanExecuteRoutedEventArgs e)
{
  e.CanExecute = !String.IsNullOrEmpty(e.Parameter as
   string);
}
private void Save_Executed(object sender,
   ExecutedRoutedEventArgs e)
{
  MessageBox.Show(e.Parameter.ToString());
}
Custom routed UI command.

Figure 4-5. Custom routed UI command.

Custom commands with ICommand

Custom RoutedUICommands solve the problem of getting rid of all those nasty OnClick event handlers, consolidating execution code into one event handler and bringing along the goodness of the CanExecute event handler to enable a more dynamic and intuitive user interface.

To truly achieve Separation of Concerns by removing the implementation from the code behind, implement the commands from the ground up starting with the ICommand interface. The interface for ICommand contains the CanExecute and the Executed event handlers as well as the CanExecuteChanged event.

The code in Listing 4-9 shows an example custom Save command. There are some differences to consider:

  • The sender and CanExecuteRoutedEventArgs/ExecuteRoutedEventArgs parameters are not in the signature for the event handlers. In their place is a single parameter of type object. This is the "parameter" object passed in from the UIElement.

  • The CanExecute event handler returns a bool. The return value is the mechanism for enabling/disabling commands (instead of setting the CanExecute property of the event argument).

  • The command does not get set in the CommandBindings XAML, but instead uses the CanExecuteChanged event to tie into the CommandManager system. To enable the correct handling of the custom command by the Command subsystem, the RequerySuggested events get hooked into the CanExecuteChanged event.

  • The ICommand interface doesn't have a Text property. This is only necessary if your code uses binding to populate the labels for MenuItems and Buttons bound to the command. The sample code adds a Text property to enable this, but since it is a simple property and not tied into the Dependency or RoutedEvent subsystems, MenuItems will not automatically populate the Header.

Example 4-9. CustomSaveCommand

public class CustomSaveCommand : ICommand
{
    public string Text { get; set; }
    public CustomSaveCommand(string text)
    {
        Text = text;
    }
    public void Execute(object parameter)
    {
        //Insert Actual "Save" code here
        //Display feedback message to user
        MessageBox.Show(parameter.ToString());
    }

    public bool CanExecute(object parameter)
    {
        return !String.IsNullOrEmpty(parameter as string);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
}

In the sample, the custom command is instantiated through a static property in the code-behind the same way the custom RoutedUICommand was in the preceding example. The next section details a much better way to handle exposing the commands to the XAML.

Separation of Concerns and testability

The end result for the Window with the custom SaveCommand has the same look and features as the preceding example. The difference between the two is that the business logic is now in a wholly self-contained class that is independent of the display mechanism (in this case, WPF).

This allows for execution of the code in the custom command class without having to work (some would say "fight") with the CommandManager subsystem or the WPF rendering engine. It also allows for the command to be reused for more than one Window.

Note

The unit tests in this chapter use MbUnit, which is part of Gallio. Any test framework will work (including NUnit, XUnit, MSTest, and so forth). Gallio can be found at http://www.gallio.org.

First unit test

The first unit test verifies that the Text property of the instantiated command gets populated in the constructor. The complete unit test is shown in Listing 4-10. The Arrange, Act, and Assert comments are not usually included in the unit tests. They are included in Listing 4-10 to demonstrate the structure of a unit test.

To execute the test, run Gallio Icarus — the GUI test runner that ships with Gallio. Click on Add Files, navigate to your compiled test project, and then click on Start to run the tests.

Example 4-10. Unit Testing the Constructor Setting the Text Property

[Test]
public void Should_Set_Text_Property_In_The_Constructor()
{
    //Arrange
    CustomSaveCommand command;
    //Act
    string expectedValue = "Save";
    command = new CustomSaveCommand(expectedValue);
    //Assert
    Assert.AreEqual(expectedValue, command.Text);
}

Test positive and negative conditions

When writing unit tests, it's important to test success as well as failure conditions. For the CanExecute method of the custom Save command, that means tests must cover when the parameter is null or empty in addition to having a string value. These tests are shown in Listing 4-11.

Example 4-11. Testing the CanExecute Event Handler

[Test]
public void Should_Not_Execute_If_Parameter_Is_Null()
{
    ICommand command = new CustomSaveCommand("Save");
    bool canExecute = command.CanExecute(null);
    Assert.IsFalse(canExecute);
}
[Test]
public void Should_Not_Execute_If_Parameter_Is_Empty_String()
{
    ICommand command = new CustomSaveCommand("Save");
    bool canExecute = command.CanExecute(string.Empty);
    Assert.IsFalse(canExecute);
}
[Test]
public void Should_Execute_If_Parameter_Is_Not_Empty_String()
{
    ICommand command = new CustomSaveCommand("Save");
    bool canExecute = command.CanExecute("Test");
    Assert.IsTrue(canExecute);
}

Get Your ViewModel On

Design patterns have been around for quite some time. Over time, some of the older patterns lose relevance, and new ones get created to fill needs of current development. One new pattern that has gained significant traction with WPF and Silverlight is the Model-View-View Model pattern. Commonly referred to as "ViewModel" (although this is still very much in flux, even within the walls of Microsoft), this pattern is very similar to Martin Fowler's Presentation Model Pattern.

Note

You can read Martin Fowler's paper on the Presentation Model pattern at http://martinfowler.com/eaaDev/PresentationModel.html.

Who cares?

I know what you're thinking. "Why can't I just sit down and start coding up a WPF application using all the goodies I've learned so far?" The short answer is that you can. But should you? That debate still rages on among those who like to sit around and debate these things. Using a user interface pattern (such as ViewModel) that promotes separation of concerns, cuts down on repeated code, increases testability, and reduces complexity can't hurt.

"Won't it take longer to develop an application using one of these patterns?" That is a common question, and the answer is a very definite, "It depends." Once developers fully understand the objectives and techniques, velocity (the amount of work accomplished by a team in a given period of time) starts ratcheting up. Getting to that level of understanding (especially if several variations are attempted) can take time and usually involves a bit of thrashing along the way.

When there is a change request (users call them "bugs," but I prefer a different nomenclature), if you are using a presentation pattern that ensures separation of concerns, it is clear where to go in the codebase to resolve the issue. Traditional development styles (like those techniques commonly used in Windows Forms) make it all too easy to place business code into event handlers and code-behind files, mixing concerns and dependencies.

Tradition!

To fully understand why the ViewModel pattern helps, you need to understand the parts of a "traditional" application architecture.

Data Access Layer (DAL)

The DAL is the set of classes and methods that get the data out of the data store (such as SQL Server) and populate the Model (see next item). It is also responsible for persisting any changes to the data back to the data store.

Model

The Model is the data that composes your application — not the data store itself (for example, the database), but the object graph that represents the data for your application. In a sales application, example objects could be classes like Customer, SalesRegion, and SalesPerson.

Business Layer (BL)

The BL is the implementation of the business rules for the application. This layer ensures that the data in the Model adheres to the law of the land.

View

The View represents the pieces of the application that interact with the user. For WPF, this is the collection of Windows that compose the application.

The biggest gap with displaying an object graph (Model) in a View is that applications seldom display only one type of object at a time. If the Window allows for editing a customer, then it probably needs to display the sales regions, sales people, and so forth.

Combining multiple objects into a data object clouds the Model, and placing all that code into the view places too much knowledge in the View — not to mention a total testability fail. The compilation of the required parts of the object graph should not detract from any other part of the application.

The Command Objects are another consideration. There isn't a tidy place in the traditional application layers to place the custom commands. The code contained in the commands is (typically) Business Logic, but the Window needs to bind to the commands, and is therefore specific to the View.

Introducing the ViewModel

The ViewModel fills that gap. It is designed to be a single class that pulls in all the necessary data points and commands into a one-stop shop for a particular view. Each view typically has its own ViewModel, but that is entirely dependent on your particular application.

As Chapter 3 discusses, WPF automatically monitors any class that implements either INotifyPropertyChanged (for items bound to a property of a class) and/or INotifyCollectionChanged (for items bound to a collection of items). These interfaces should be implemented in one of two camps — the ViewModel or the Model.

Implementing those two interfaces in the ViewModel is the more academic, textbook implementation. This is because it separates user interface code from the Model. It also requires a lot of additional work, because it entails recoding all the properties and collections of your Model to include raising the proper events.

Implementing in the Model reduces work, because it merely entails adding a few lines of code into properties already being implemented in the classes. A main argument against Model implementation revolves around code reuse. For example, if the Model is also used by an ASP.NET application, those events are still raised but no one is listening. This could potentially present a performance issue. Of course, if you use the same model for WPF and non-WPF Views, then a simple flag passed into the constructor of the Model classes indicating whether the events should be raised or not resolves that issue.

Both ways are valid implementations. Your application and specific situation will most likely dictate where those interfaces are implemented.

In Chapter 3, you discover that if a control doesn't have an explicit DataContext, it is inherited from the closest parent in the control tree that does have a DataContext explicitly assigned.

When developing WPF applications using the ViewModel pattern, the instantiated ViewModel becomes the Window's (or user control's) DataContext.

Show me the code!

Note

The full code for the ViewModel samples is in the project Chapter4ViewModels and Chapter4ViewModelsTests in the Chapter4 Solution.

Just what are we building?

The Window (or View, to use "architecture speak") is a simple customer maintenance form. The user can select a customer and edit his name and sales region. Clicking the Add Customer button will add a customer to the list. You're right — not very realistic, but it demonstrates the ViewModel principles. Figure 4-6 shows the completed sample user interface.

The Customer Maintenance Window.

Figure 4-6. The Customer Maintenance Window.

The model

Okay, enough talk. For the sample ViewModel, we need to define a Model.

Listing 4-12 shows the base class from which all the Model classes will derive. The base class implements the INotifyPropertyChanged interface as well as the IsDirty property.

Example 4-12. ModelBase

public class ModelBase : INotifyPropertyChanged
{
    public bool IsDirty { get; private set; }
    public event PropertyChangedEventHandler PropertyChanged;
    internal void NotifyPropertyChanged(object sender, string
   propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(sender, new PropertyChangedEventA
   rgs(propertyName));
        }
        IsDirty = true;
    }
}

Listings 4-13 and 4-14 show the Customer and SalesRegion classes that will populate the View. For each property in the class (except for the primary key and the collection properties), there is a check to see if the value of the property is being set to a new value. If it is new, then the PropertyChanged event is raised. The NotifyPropertyChanged method also sets the IsDirty flag to True to indicate that the model has changes that need to be persisted.

The primary key (in this example) is being set by the data store, so it will never change in the view. Because the property changed event will never need to be raised, the property can be coded as an automatic property.

Example 4-13. The Customer Model Class

public class Customer : ModelBase
{
    private string _name;
    private SalesRegion _region;
    public int ID { get; set; }
    public string Name
    {
        get { return _name; }
        set
        {
            if (value == _name)
            {
                return;
            }
            _name = value;
            NotifyPropertyChanged(this, "Name");
        }
    }
    public SalesRegion SalesRegion
    {
        get { return _region; }
        set
        {
            if (value == _region)
            {
                return;
}
            _region = value;
            NotifyPropertyChanged(this, "SalesRegion");
        }
    }
}

Example 4-14. The SalesRegion Model Class

public class SalesRegion:ModelBase
{
    private string _name;
    public int ID {get; set;}
    public string Name
    {
        get { return _name; }
        set
        {
            if (value == _name)
            {
                return;
            }
            _name = value;
            NotifyPropertyChanged(this, "Name");
        }
    }
}

Model unit tests

There isn't much to test in the model. You don't typically write tests against the .NET Framework itself — one has to assume that it works! The only real logic in this sample is setting of the IsDirty and the raising of the PropertyChanged event when something changes.

The first test is to verify that the IsDirty flag gets set when a property changes, and it is very straightforward. We create a new Customer, assert that the IsDirty flag is False, make a change, and then assert that the IsDirty flag is True. This test is shown in Listing 4-15.

Example 4-15. Testing the IsDirty Flag

[Test]
public void Should_Set_Is_Dirty_On_Property_Change()
{
    var sut = new Customer();
    Assert.IsFalse(sut.IsDirty);
    sut.Name="New Name";
    Assert.IsTrue(sut.IsDirty);
}

The second test is much more involved, because it tests the raising of the PropertyChanged event. We have to create a subscriber to listen for this event. Windows (and the WPF rendering engine) automatically attach to this event, but we don't want to re-create the rendering engine just to test one method. To test the event, create a subscriber, raise the event, and then assert that the handler of the event was executed.

Tests of this type are typically done with a mocking framework, such as RhinoMocks (the tool used in the samples). Mocking frameworks allow tests for behavior in addition to state, and since the test needs to validate that an event was raised, RhinoMocks is the perfect fit. A deep dive into mocking and behavior testing is beyond the scope of this book. Look at the code, digest it, and tinker with it. It's a great way to expand your testing knowledge!

Mocking frameworks create proxy objects based on interfaces. For the single event, create an interface (shown in Listing 4-16) that has the required signature for the event handler — in this case, the PropertyChanged event.

Example 4-16. The Event Subscriber

public interface IPropertyChangedSubscriber
{
    void Handler(object sender, PropertyChangedEventArgs e);
}

The test starts off by creating a mock of the subscriber and registering the PropertyChanged event with the handler. The test acts on the Customer object by changing the name and then asserts that the handler was called. The Arg<object>.Is.Anything syntax tells RhinoMocks to not test the arguments for equality. Again, the test is just verifying that the event is raised when a property on the Customer object is updated. See the code in Listing 4-17.

Example 4-17. Testing an Event Was Raised

[Test]
public void Should_Raise_Property_Changed_Event_On_Property_
   Change()
{
    var sut = new Customer();
    var eventArgs = new PropertyChangedEventArgs(string.
   Empty);
    var subscriber = MockRepository.GenerateMock<IPropertyCha
   ngedSubscriber>();
    sut.PropertyChanged += subscriber.Handler;
    sut.Name = "New Name";
    subscriber.AssertWasCalled(x => x.Handler(Arg<object>.
    Is.Anything, Arg<PropertyChangedEventArgs>.Is.Anything));
}

Note

The RhinoMocks tool can be found on the Web at http://ayende.com/projects/rhino-mocks/downloads.aspx. For a good description of mocks versus stubs, see Martin Fowler's paper "Mocks Aren't Stubs," located at http://martinfowler.com/articles/mocksArentStubs.html.

Model repositories

The repository pattern is commonly used for Line of Business applications to move data between the data store and the model classes. For the sample ViewModel, I've included a very simple interface (shown in Listing 4-18) that has a GetAll method and an Update method (not even remotely a complete repository, but all that we need for the examples). Note the use of generics to enforce strong typing in the repositories that implement this interface.

Example 4-18. The Repository Interface

public interface IRepository<T>
{
    IList<T> GetAll();
    bool Update(T model);
}

The repositories in the samples return hard-coded values instead of connecting to a data store. It's common practice to create classes that are used only for testing or prototyping. The convention I prefer is to call them out by appending Fake to the name (as shown in Listing 4-19) so other developers have no doubt about their intended purpose. Additionally, the examples don't implement the Update methods because they aren't used for the ViewModel samples shown.

Example 4-19. Fake SalesRegion Repository

public class SalesRegionRepositoryFake :
   IRepository<SalesRegion>
{

   public IList<SalesRegion> GetAll()
   {
       var list = new ObservableCollection<SalesRegion>
       {
           new SalesRegion {ID = 1, Name = "East"},
           new SalesRegion {ID = 2, Name = "Central"},
           new SalesRegion {ID = 3, Name = "West"}
       };
       return list;
   }

   public bool Update(SalesRegion region)
   {
       throw new NotImplementedException();
   }
}

To create a customer, a list of Sales Regions must be available, so the Customer Repository Fake (as shown in Listing 4-20) uses Constructor Injection to insert the allowable values into the repository. It could have created its own list, but that would have thrown off the binding in XAML since the objects would be different.

Example 4-20. Fake Customer Repository

public class CustomerRepositoryFake : IRepository<Customer>
{
    readonly IList<SalesRegion> _salesRegions;

    public CustomerRepositoryFake(IList<SalesRegion>
   salesRegions)
    {
       _salesRegions = salesRegions;
    }
public IList<Customer> GetAll()
    {
        var list = new ObservableCollection<Customer>();
        var customer = new Customer {Name = "Jane Doe", ID=1,
   SalesRegion = _salesRegions[0]};
        list.Add(customer);
        customer = new Customer {Name = "John Smith", ID=2,
   SalesRegion = _salesRegions[1]};
        list.Add(customer);
        customer = new Customer { Name = "John Doe", ID = 3,
   SalesRegion = _salesRegions[2] };
        list.Add(customer);
        return list;
    }
    public bool Update(Customer customer)
    {
        throw new NotImplementedException();
    }
}

The Add Customer command

Interestingly enough, using the ViewModel pattern, the commands can be developed prior to the view, enabling Test Driven Development for the commands. Using the same approach discussed in the "Commanding Attention" section earlier in this chapter, a CommandBase class (shown in Listing 4-21) is extracted to hold the common properties and the CanExecuteChanged event.

Example 4-21. CommandBase Class

public abstract class CommandBase : ICommand
{
    public string Text { get; internal set; }
    public abstract void Execute(object parameter);
    public abstract bool CanExecute(object parameter);
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
}

The AddCustomerCommand (shown in Listing 4-22) will take the Customer list as a parameter and add another customer to the list. In this example, it's a hard-coded set of values, but in reality you would probably have another Window (or some data entry mechanism) to gather the required information.

The CanExecute event handler checks that the parameter is a List<Customer>. There is an additional check in the Execute method. It is essentially redundant — the command should never execute if the parameter is not an IList<Customer>. However, defensive programming kicks in, and I always check again to avoid the possibility of throwing an error.

Example 4-22. AddCustomerCommand

public class AddCustomerCommand : CommandBase
{
    public AddCustomerCommand()
    {
        Text = "Add Customer";
    }
    public override void Execute(object parameter)
    {
        var list = parameter as IList<Customer>;
        if (list == null)
        {
            return;
        }
        list.Add(new Customer { ID = 4, Name = "New Customer" });
    }
    public override bool CanExecute(object parameter)
    {
        return parameter is IList<Customer>;
    }
}

The Add Customer Command unit tests

The tests for the AddCustomerCommand are similar to the tests from the "Commanding Attention" section, earlier in this chapter. In the code in Listing 4-23, the first three tests validate the CanExecute event handler; the last test validates the Executed event handler.

Example 4-23. The AddCustomerCommand Unit Tests

[Test]
public void Should_Not_Execute_If_Parameter_Is_Null()
{
    var cmd = new AddCustomerCommand();
    var canExecute = cmd.CanExecute(null);
    Assert.IsFalse(canExecute);
}
[Test]
public void Should_Not_Execute_If_Parameter_Is_Not_List_
   Customer()
{
    var cmd = new AddCustomerCommand();
    var canExecute = cmd.CanExecute("test");
    Assert.IsFalse(canExecute);
}
[Test]
public void Should_Execute_If_Parameter_Is_List_Customer()
{
    var cmd = new AddCustomerCommand();
    var canExecute = cmd.CanExecute(new List<Customer>());
    Assert.IsTrue(canExecute);
}

[Test]
public void Should_Add_Customer_To_List_On_Execute()
{
    var cmd = new AddCustomerCommand();
    var customers = new List<Customer>();
    var count = customers.Count;
    cmd.Execute(customers);
    Assert.AreEqual(count+1, customers.Count);

}

The ViewModel

So, you're thinking to yourself at this point, "There's been a lot of code slung so far. And we haven't even touched the ViewModel yet?" And you're right. However, as you will soon see, the ViewModel becomes a rather trivial exercise because of the setup that we have already done. There are just three properties in the ViewModel and two lines of code that need to be run in the constructor (and one of them is required by the XAML rendering engine). Yep. That's it.

The image in Figure 4-6 contains two combo boxes that need to be populated. One of the tenants of the ViewModel pattern is to provide a one-stop shop for the View. In addition to the main data (Customers), this includes any reference data (Sales Regions). The ViewModel (shown in Listing 4-24) contains these IList<T> as properties that can be bound to in the view and (in this example) are populated in the constructor.

The Window also contains a single Button that needs to be bound to the AddCustomerCommand. Commands require a bit more plumbing, because they must be instantiated prior to use. The technique shown in this sample is just in time instantiation and is meant to cut down on resource consumption. If the button never gets clicked, why create the command in memory?

Example 4-24. The ViewModel

public class CustomerMaintenanceViewModel
{
    ICommand _addCustomerCmd;

    public CustomerMaintenanceViewModel()
    {
        Regions = new SalesRegionRepositoryFake().GetAll();
        Customers = new CustomerRepositoryFake(Regions).
   GetAll();
    }
    public IList<Customer> Customers { get; set;}
    public IList<SalesRegion> Regions { get; set;}

    public ICommand AddCustomerCmd
    {
        get { return _addCustomerCmd ?? (_addCustomerCmd =
   new AddCustomerCommand()); }
        set { _addCustomerCmd = value; }
    }

}

Testing the ViewModel

There's actually nothing to test in this ViewModel, because it's all been tested elsewhere. But if there was code in a ViewModel that needed testing, it can be tested like any other class library.

The View

There are a couple of items worth mentioning when it comes to the view. First and foremost, the constructor for the view needs to assign its DataContext to an instance of the ViewModel (see the bolded line in Listing 4-25).

Example 4-25. The View Code-Behind

public partial class CustomerMaintenance : Window
{
    pubblic CustomerMaintenance()
    {
        InitializeComponent();
        DataContext = new CustomerMaintenanceViewModel();
    }
}

Wait! Didn't I say we want to remove all code from the code-behind? No, not all code. Almost all code. Event handlers stuffed with business logic, definitely. But you have to have two lines in the constructor: InitializeComponent(), which renders all the XAML, and the DataContext assignment. You might have cases for additional code living in the code-behind, and those cases might be perfectly valid. Just use critical thought before you start adding code in places where it can't be tested or reused.

The Command Binding expressions become very different using the ViewModel pattern. They actually become quite a bit easier as shown in Listing 4-26. Since the base class hooks the Command into the CommandManager, the need for the Windows.CommandBindings section is eliminated.

Example 4-26. The Add Customer Button XAML

<Button HorizontalAlignment="Right" Margin="3,0,3,0"
   Command="{Binding Path=AddCustomerCmd}"
   CommandParameter="{Binding Path=Customers}"
Content="{Binding RelativeSource={RelativeSource
   Mode=Self},Path=Command.Text}"
/>

The Content hasn't changed from the earlier examples, but the Command and CommandParameter assignments have. The DataContext for all controls roll up the element tree looking for the first DataContext. Because the only DataContext is set at the Window level (in the constructor), all elements have as their DataContext the ViewModel. So binding is reduced to setting the Path to the property of the ViewModel (in this case, the AddCustomerCmd for the Command, and the Customers property for the Command Parameter).

Likewise, ComboBoxes bind their ItemsSource property to the IList<T> properties in the ViewModel. Listing 4-27 shows the XAML for the two ComboBoxes on the Window.

Example 4-27. ComboBoxes XAML with ViewModel

<ComboBox ItemsSource="{Binding Path=Customers}"
   DisplayMemberPath="Name"/>
<ComboBox ItemsSource="{Binding Path=Regions}"
   DisplayMemberPath="Name"
   SelectedItem="{Binding ElementName=CustomerList,Path=Selec
   tedItem.SalesRegion}"
/>

The second ComboBox shows the power of WPF data binding. The SelectedItem should be set to the value of the SalesRegion property for the Customer. To do this through binding, the item is set to the SelectedItem of the CustomerList. This returns a Customer object, allowing any property on that Customer to be selected in the Path (in this case, the SalesRegion property).

Wrap up

I was asked recently if using the ViewModel pattern is worth it since it "seems like a lot of extra work." This is a common theme among WPF developers currently, and it isn't surprising considering the newness of the pattern, all the current variations in the wild, and conflicting opinions on the subject.

In short, it is absolutely worth it. The biggest benefit the ViewModel brings to the table is true separation of concerns with a side of testability. Any time you can reduce the dependence on manual user testing and increase automatic test coverage, it's a win. Increased code isolation, improved capabilities for code reuse, and reduced complexities all come with the package. And there isn't "more" code developed — it's just moved out of the code-behind files for the Windows.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.74.154