Commanding Support

Command Parameters

Overview

The Notoric commanding supports one important feature and that is the parameter values binding. Any input or input / output parameter of a command can be bound to a compatible parameter of another command. Compatible means that the parameters must have compatible value types (more precisely the value of the parameter being bound has to be assignable from the parameter value to which the binding is made). And in this manner a command tree is created. When the root command is then executed, it first executes all the subcommands to which it is bound that were not yet executed and this process continues recursively until the leaf command is reached. Note that you can also bind multiple parameters of one command to multiple parameters of another command.
For this purpose the command parameters are implemented in a way that is similar to dependency properties in the Windows Presentation Foundation. Each command have something that is called ParameterSet which is a dictionary mapping the names of the parameters to their values. The parameters from the command parameter set can then be accessed through a pair of methods SetParameterValue and GetParameterValue that takes the name of the requested parameter and to help security they are strongly typed (by means of generic type parameter). This cannot defend the caller to use the wrong type, but helps during writing the code. Anyway, if an incompatible value is passed, the InvalidCastException is thrown. In order to simplify the access to the parameters the command can define wrapper CLR properties.
The identification of the command parameter is weaker than in the case of dependency properties (simple string versus static class field), but the implementation simplified considerably and if anytime a wrong parameter name is passed to the command, an exception is thrown.
In order to determine which commands need to be executed the parameter value can exist in two states: NotKnown and Computed.

Implementation

Command Parameters Scheme
Above you can see a simplified UML class diagram showing the parameters implementation:
  • Each command holds one instance of a ParameterSet class
  • The ParameterSet holds the Parameters of the command in a dictionary (Parameter Name -> Parameter instance)
  • Each Parameter can reference another command that is then responsible for computing its value. The value binding is done by sharing the ValueHolder instance (the value holder of the subcommand parameter is used).

The binding of the parameters is done through a call to BindParameterToCommand method that accepts three parameters: name of the parameter that is being bound, reference to the subcommand and the name of the subcommand parameter to which the value is being bound. If the parameters have incompatible types the IncompatibleTypesException is thrown.

Example:
Suppose you have two commands: Command1 with a parameter named MyValue and Command2 with a parameter named Source. Now you want the Command1.MyValue to take its value from the Command2.Source (the parameters have compatible types). So you call Command1.BindParameterToCommand("MyValue", Command2, "Source");

Notes on Parameters Binding

  • In the default implementation a command can execute (CanExecute returns true) if and only if all of its input parameters have computed values or are bound to commands that can execute.
  • All the subcommands whose bound values are not computed when the command executes are executed, no lazy evaluation is performed.
  • The subcommands are executed before the command is operation is performed, but the order of their execution is undefined and no presumption should be made on this purpose.
  • When a command is being undone, its operation is undone first and then the subcommands that were executed during the command execution are undone. If some of the subcommands was executed before the command execution, it is not undone here.

Command Classes Hierarchy

The commanding library comes with three important classes that are shown on the diagram bellow:
Hierarchy of the Base Command Classes
  • CommandBase implements the basic features: Parameter set manipulation and parameter binding, the command name and the LastExecuted time stamp.
  • SingleUseCommandBase extends the CommandBase functionality with support for commands that can be executed only once. The execution of the command is blocked when it is executed. The class defines one abstract method called CommandOperation where the command logic is put in its subclasses.
  • UndoableCommandBase extends the CommandBase functionality with support for commands that can be undone and redone after their execution and also with the management of the corresponding command stacks. It defines three abstract methods where the command logic is put in the subclasses:
    • CommandOperation is called when the command executes for the first time
    • UndoOperation is called when the command is undone
    • RedoOperation is called when the comman is redone

UndoableCommandBase

This class is a bit more complex and is worth its own paragraph.
In order to ensure the correct function undoable commands manage their execution state themselves. This means that one can only call the Execute method and the command either executes, undoes or redoes its operation depending on its current state. When an undoable command has subcommands it is desirable that only the root command is put on the command stack. In the same time we want the parameter binding functionality to work throughout the whole tree. Hence we need one additional stage in the command execution sequence:
  • Execute method checks the current ExecutionState and calls the appropriate <Execute | Undo | Redo>Command method. Once the call returns, this method updates the ExecutionState and puts the command on the appropriate command stack (removing it from the previous one if necessary).
  • <Execute | Undo | Redo>Command method invokes the corresponding method on the subcommands and calls the appropriate <Command | Undo | Redo>Operation method.
  • <Command | Undo | Redo>Operation method is implemented in a subclass and contains the logic of the concrete command

Execution Sequence of Undoable Commands

Bellow is shown the sequence diagram of the UndoableCommandBase.Execute call for the case where the ExecutionState is equal to NotExecuted (i.e. the command is executed for the first time).
You can observe the following steps:
  1. The CanExecute method is called to verify that the command can execute. If the test fails an exception is thrown.
  2. The ExecuteCommand method is invoked
  3. For each parameter whose value is bound to a subcommand and is not yet computed the corresponding subcommand is executed via a call to its ExecuteCommand method.
  4. The CommandOperation method is invoked leaving the subclass to perform the logic of the command
  5. The command is put on the undo command stack
  6. The CanExecuteChanged event is raised because the ExecutionState has just changed
UndoableCommand.Execute Sequence Diagram

Last edited Dec 8, 2009 at 5:16 PM by Luk, version 6

Comments

No comments yet.