November 2014

Volume 29 Number 11

Dieser Artikel wurde maschinell übersetzt.

MVVM - WPF-Befehle mit dem Statuscomputer-Muster

By arquin Vaughan -Scott | November 2014

State Machines

State machines come in different flavors, but they’re essentially a design pattern that represents a process that moves from one state to another. User actions (also called triggers) cause the state machine to transition between states. Rules restrict which actions are allowed for each state.

Finite state machines only allow one state at a time. Hierarchical state machines allow states and sub-states. Hierarchical state machines are often more useful because the sub-states inherit all the attributes of their super-state. This can reduce the amount of configuration required.

For example, consider a user clicking a Search button: The application transitions to a Searching state. While in this state, the user should be prevented from performing other actions (with the possible exception of a Cancel action). The Searching state would therefore have a rule that prevents or ignores all actions except for the Cancel action. Some state machine implementations also allow entry and exit actions. You can have this logic executed when a state is entered and exited.

Command Structure

Like a genie in a bottle, commands are there to do their master’s bidding, but what is a command? Commands have their origin in command-line interfaces, in which the user is required to type in a directive that is then interpreted by the application.

This concept has evolved in modern interfaces to abstract a user’s intended action. For example, if a user wants to copy some text, the command is Copy Text. The user can achieve this by clicking a menu item, right-clicking the mouse button or even using keyboard controls (CTRL+C). How the command is implemented depends on the underlying application and the framework upon which it’s built.

WPF implements the command concept via the ICommand interface. This is part of the Microsoft .NET Framework. This interface has two methods and an event:

  • void Execute(object parameter)—This executes code when the command is invoked.
  • bool CanExecute(object parameter)—This determines if the command can be invoked.
  • event EventHandler CanExecuteChanged—This informs the framework that conditions affecting the CanExecute method have changed. This is generally handled by the WPF framework.

Basically, a command source such as a button or menu item implements the ICommandSource interface. This interface has a property named Command of type ICommand. By binding this property to an ICommand implementation on the ViewModel, the control will invoke the Execute method. You can also have it enabled and disabled based on the CanExecute method result. If a control acting as a command source doesn’t have an ICommand property (which, unfortunately, is fairly common), then you can use an event to command technique.

The implementations of ICommand built in to the .NET Framework are the RoutedCommand and RoutedUICommand. These route events up and down the visual tree and aren’t suitable for use with the MVVM pattern. The RelayCommand by Josh Smith and the DelegateCommand that’s part of the Prism framework are commonly used implementations for the MVVM pattern.

The source code accompanying this article contains a Visual Studio 2013 solution that demonstrates the principles of the state machine and how to use it to manage commands. The sample application lets a user search through a list of employees, select an employee and then display a dialog for editing employee details (see Figure 1).

The List of Employees Loaded and Ready for Editing
Figure 1 The List of Employees Loaded and Ready for Editing

Design the State Machine

The first step in the design process is to define the section of the application using a flow chart or state diagram. Figure 2 shows a flow chart diagram for the employee manager screen. It also includes blocks that indicate a potentially long-running process such as Searching. You need to handle these in a special way and prevent the user from re-running the operation while it’s busy. Creating these intermediary “busy” blocks is especially important with the new async functionality in the .NET Framework, as control returns to the user and he could potentially try and run the same action again resulting in reentry.

Flow Chart Showing Process of Employee Manager Screen
Figure 2 Flow Chart Showing Process of Employee Manager Screen

The second step in the design process is to define any commands that let the user interact with the application. From the employee manager screen, the user can Search, Edit an Employee and then End Editing. The user also drives the process of Selecting and Deselecting an employee, however, these aren’t managed as commands. They’re handled as data binding on a DataGrid control. The commands are now mapped onto the workflow arrows (or flow of control) at the relevant points, as shown in Figure 2.

Implement the State Machine

You don’t have to create a state machine framework from scratch, as there are many freely available libraries. The only option within the .NET Framework is the Workflow Foundation (WF) State Machine Activity. This is too complex for the problem I’m trying to solve here, but it’s great for long-running persistent workflows. After some preliminary research, I settled on the Stateless state machine library, which is available as a NuGet package at bit.ly/ZL58MG.

I can now use the flow chart I created in the design phase to create a list of states (each block in the flow chart) and the triggers (each arrow in the flow chart). Stateless uses generic types for states and triggers, so I’m going to go ahead and use an enumeration for both:

public enum States
{
  Start, Searching, SearchComplete, Selected, NoSelection, Editing
}
public enum Triggers
{
  Search, SearchFailed, SearchSucceeded, Select, DeSelect, Edit, EndEdit
}

Once the enumerations are defined, I need to configure each state using the fluent interface. The important options are:

  • SubstateOf(TState state)—indicates a state has a super-­state and will inherit all its configurations.
  • Permit(TTrigger trigger, TState targetState)—allows a state to transition to the target state via the trigger.
  • Ignore(TTrigger trigger)—causes the state to ignore the trigger if its fired. 
  • OnEntry(Action entryAction)—causes an action to execute when the state is entered.
  • OnExit(Action exitAction)—causes an action to execute when the state is exited.

There will be an exception raised by the state machine if a trigger is fired in a state without a valid configuration. This is the configuration for the Searching state:

Configure(States.Searching)
  .OnEntry(searchAction)
  .Permit(Triggers.SearchSucceeded, States.SearchComplete)
  .Permit(Triggers.SearchFailed, States.Start)
  .Ignore(Triggers.Select)
  .Ignore(Triggers.DeSelect);

The OnEntry action executes the search process and the Permits allow the relevant triggers to fire. The Ignores prevent the View from firing the Select and DeSelect triggers when the DataGrid control binds to the underlying data source (an annoyance that happens with most list controls in WPF).

The state machine also exposes two important methods:

  • void Fire(TTrigger)—This transitions the state machine using the previous configurations.
  • bool CanFire(Trigger trigger)—This returns true if the current state allows the trigger to be fired.

These are the key methods required for creating commands. They perform the execute and can execute logic.

Bind Commands to the State Machine

The MVVM pattern exposes a property implementing the ICommand interface on the ViewModel. Creating this command property is now a simple matter of binding its Execute and CanExecute methods to the state machine’s Fire and CanFire methods, respectively. Create an extension method to centralize this logic:

public static ICommand CreateCommand<TState, TTrigger>(
  this StateMachine<TState, TTrigger> stateMachine, TTrigger trigger)
    {
      return new RelayCommand
        (
          () => stateMachine.Fire(trigger),
          () => stateMachine.CanFire(trigger)
        );
    }

Once this extension method is in place, create ICommand properties on the ViewModel (refer back to the flow diagram in Figure 2 for the commands identified during the analysis phase):

SearchCommand = StateMachine.CreateCommand(Triggers.Search);
EditCommand = StateMachine.CreateCommand(Triggers.Edit);
EndEditCommand = StateMachine.CreateCommand(Triggers.EndEdit);

Bind the View to the ViewModel Command

For a control that acts as a command source, you can have its Command property bound to the ViewModel’s ICommand property. The sample application has two buttons and menu items bound to the command properties on the ViewModel:

<Button ToolTip="Search" VerticalAlignment="Center" 
  Style="{StaticResource ButtonStyle}"
  Command="{Binding SearchCommand}">
  <Image Source="Images\Search.png"></Image>
</Button>

Now the command is bound directly to the state machine. It will fire the configured trigger when executed, but more important, it will be disabled if that trigger isn’t allowed for the current state. This takes care of the tricky can execute logic, and it’s all neatly configured within the state machine. Figure 3 shows the employee manager screen while it’s busy searching. Note the Search command is disabled as the Search trigger isn’t allowed for the Searching state.

Busy Animation in the Search Dialog
Figure 3 Busy Animation in the Search Dialog

Additional Benefits

Once you’ve implemented the state machine, you can also bind other visual elements to its state. When the search function is busy executing (and keep in mind this could be a long-running operation within an asynchronous method), it’s desirable to show the user a busy indicator. Figure 3 shows an animated image displayed only when the state machine is in the Searching state. Do this by creating a custom converter that converts the state machine state into a Visibility value:

public class StateMachineVisibilityConverter : IValueConverter
  {
    public object Convert(object value, Type targetType,
      object parameter, CultureInfo culture)
    {
      string state = value != null ? 
        value.ToString() : String.Empty;
      string targetState = parameter.ToString();
      return state == targetState ? 
        Visibility.Visible : Visibility.Collapsed;
    }
 }

The animated image is then bound to the state machine state using the custom converter:

<local:AnimatedGIFControl Visibility="{Binding StateMachine.State,
                          Converter={StaticResource StateMachineConverter},
                          ConverterParameter=Searching}"/>

You can apply the same principle to the editing dialog shown over the employee manager screen in Figure 4. When the state machine is in the Editing state, the dialog becomes visible and the user can edit the selected employee’s details.

The Editing Dialog State
Figure 4 The Editing Dialog State

State of Mind

The state machine pattern not only solves the problems associated with command logic, but also creates a state of mind that allows for better application analysis. It’s easy to think of commands as controls that execute some sort of logic. What’s often neglected is determining when to allow the command to execute. The command-state machine pattern addresses these issues early on in the design process. They’re naturally part of the state machine configuration. States machines have simplified my ViewModel code and can do the same for your applications.

Additional References

  • State Machine: It’s surprisingly difficult to find a well-written introduction to state machines, but games developer Bob Nystrom has written a pretty good one (bit.ly/1uGxVv6).
  • WPF MVVM: The “father” of WPF-MVVM Josh Smith provides an implementation of the ICommand interface, the RelayCommand, in a February 2009 MSDN Magazine article (msdn.microsoft.com/magazine/dd419663).
  • Commands: Official MSDN documentation on WPF commanding discusses routed commands and events that are part of the .NET Framework (bit.ly/1mRCOTv).
  • Routed Commands: Brian Noyes covers routed commands in a September 2008 MSDN Magazine article. It’s a good starting point to understand the difference between routed commands and the MVVM command pattern (bit.ly/1CihBVZ).
  • Commands, RelayCommands and EventToCommand: Laurent Bugnion’s May 2013 article shows how to convert events to commands, which is useful for controls that don’t implement the ICommandSource interface (msdn.microsoft.com/magazine/dn237302).
  • Prism Framework: The official documentation for the Prism framework discusses the MVVM pattern and the DelegateCommand (bit.ly/1k2Q6sY).
  • NuGet Stateless Package: The Stateless package on the NuGet Web site comes with download instructions (bit.ly/1sXBQl2).

Tarquin Vaughan-Scott is the lead developer at InfoVest (infovest.co.za), based in Cape Town, South Africa, which creates data management solutions for the financial industry. His main interests are database design and architectures—­especially the differences between transactional and data warehouse systems. Reach him at tarquin@infovest.co.za.

Thanks to the following Microsoft technical expert for reviewing this article: Nicholas Blumhardt
Nicholas Blumhardt (Stateless) is an ex-Microsoft employee as part of the MEF team