In This Topic
Commanding Architecture
NOV UI features build-in support for implementing User Interfaces with complex commanding logic. The commanding model is fundamentally built upon the concepts of a command, command target and command source as illustrated by the following image:
In the image above we see a simple DOM hierarchy that has two command targets and two command sources.
A command target can be any input target node that can react to the commanding events that NOV UI dispatches. Typically command targets are instances of the NInputElement class, which sits pretty low in the UI Elements hierarchy (see UI Elements Hierarchy for more info). The NInputElement class has built-in support for command actions, that are managed by an instance of the NCommander class, which can be assigned to any input element. A command action is the action that is executed in response to a command triggered by either a command source or the shortcut (key gesture) associated with the command. Command actions are represented by instances of the NCommandAction class and are also responsible for the update of the possible command sources.
A command source is typically associated with a widget, and is dynamically bound with a command target. A command source raises the NCommand.QueryCommandTargetEvent event along its ancestors chain when it wants to update the widget visual state or execute the command associated with the source. The event handlers along the command source ancestors chain are considered to be Command Target Providers.
The commands are used to link the command target actions and command sources together, at a static level. They serve as contract between the source and the target.
To further clarify the commanding model, imagine the following scene:
- Command Target Provider is a command bar manager. It handles the NCommand.QueryCommandTargetEvent event and returns the Command Target 1 for Command 1 and Command Target 2 for Command 2..
- Command Source 1 and Command Source 2 are associated with two buttons that reside in a command bar of the command bar manager. The command sources are associated with Command 1 and Command 2.
- Command Target 1 is some widget, the NCommander of which has a NCommandAction for Command 1.
- Command Target 2 is another widget, the NCommander of which has a NCommandAction for Command 2.
In this imaginary scene the command actions can be executed in two ways:
1 - In Response to User Interaction with the Command Sources
- The user clicks the Command Source 1 button.
- The command source associated with the button raises the NCommand.QueryCommandTargetEvent event, which is routed along the Command Source 1 ancestors chain.
- The NCommand.QueryCommandTargetEvent event is handled by the command bar manager, which says that Command Target 1 is the target for Command 1.
- Command Source 1 raises the NCommand.ExecuteCommandEvent event, which is routed along the Command Target 1 ancestor chain.
- The NCommander of Command Target 1 invokes the command action associated with Command 1.
2 - In Response to Keyboard Shortcuts
- Command Target 1 has keyboard focus and the user presses the Command 1 shortcut (key gesture).
- NKeyboard raises the NKeyboard.KeyDownEvent event, which is routed along the Command Target 1 ancestors chain.
- The NCommander of Command Target 1 invokes the command action associated with Command 1.
Commands
Commands are the glue of the commanding model. A command is represented by the NCommand class, of which you must only create singleton instances. The following code sample creates two commands that are associated with the custom MyCommandableWidget class.
Creating Commands |
Copy Code
|
public class MyCommandableWidget : NWidget
{
public MyCommandableWidget()
{
// TODO: initialize commander here
}
static MyCommandableWidget()
{
MyCommandableWidgetSchema = NSchema.Create(typeof(MyCommandableWidget), NWidget.NWidgetSchema);
// create a command that is associated with the Ctrl+T shortcut
MyActionCommand = NCommand.Create(MyCommandableWidgetSchema, "MyCommandName1", "My Command Text1", new NShortcut(new NKey(ENKeyCode.T), ENModifierKeys.Control));
MyToggleCommand = NCommand.Create(MyCommandableWidgetSchema, "MyCommandName2", "My Command Text2", new NShortcut(new NKey(ENKeyCode.R), ENModifierKeys.Control));
}
public static readonly NSchema MyCommandableWidgetSchema;
public static readonly NCommand MyActionCommand;
public static readonly NCommand MyToggleCommand;
}
|
The MyCommandableWidget static constructor creates two singleton command instances and stores them in its static command fields. The commands are named as "MyCommandName1" and "MyCommandName2". The text associated with them is "My Command Text1" and "My Command Text2" respectively.
The command actions will execute in response to the Control+T and Control+R key gestures respectively. The command actions are discussed in the next section.
Command Actions and Commander
Command actions are the objects that execute specific commands. The command actions are represented by instances of the NCommandAction class and are contained inside an instance of the NCommander class. The following code defines a sample command action and adds it to the MyCommandableWidget commander:
Command Actions and Commander |
Copy Code
|
...
// MyCommandableWidget constructor
public MyCommandableWidget()
{
// Create a command action and add it to the commander
Commander.Add(new MyFirstCommandAction());
}
...
public class MyFirstCommandAction : NCommandAction
{
public MyFirstCommandAction() { }
static MyFirstCommandAction() { MyFirstCommandActionSchema = NSchema.Create(typeof(MyFirstCommandAction), NCommandAction.NCommandActionSchema); }
public override NCommand GetCommand()
{
return MyCommandableWidget.MyActionCommand;
}
public override bool IsEnabled(NNode target)
{
MyCommandableWidget widget = target as MyCommandableWidget;
// TODO: Returns false if action cannot be performed
return true;
}
public override void Execute(NNode target, object parameter)
{
MyCommandableWidget widget = target as MyCommandableWidget;
// TODO: Perform action on widget
}
public static readonly NSchema MyFirstCommandActionSchema;
}
|
A command action needs to reside in the commander of some input element, in order to be functional. In the code sample we create the MyFirstCommandAction and add it to the Commander of MyCommandableWidget.
A command needs to override the GetCommand() method, to tell the commanding model about the command with which it is associated.
A command needs to override the IsEnabled(...) method, to tell the commanding model whether the command can currently be executed towards the target.
A command needs to override the Execute(...) method, to execute the action on the command.
Command Sources
Command sources are represented by objects that derive from the NCommandSource abstract class. The NCommandSource is an attribute node, that is designed to be "associated" with input elements via an extended property. When a command source object is associated with an input element, it typically handles some of the input element events in order to perform a command action. For example the NButtonBaseCommandSource, subscribes for the button Click event to execute the command associated with the command source, when the button is clicked. The following code example demonstrates how to create a button, which when clicked will execute a command:
My First Command Source |
Copy Code
|
NButton button = new NButton("Click me to execute MyActionCommand");
NButtonBaseCommandSource myActionCommandSource = new NButtonBaseCommandSource(MyCommandableWidget.MyActionCommand);
NCommandSource.SetCommandSource(button, myActionCommandSource);
|
NOV comes equipped with a large set of command sources, ready to attached to the respective widgets:
Command Source |
Target Widget |
Description |
Buttons
|
NButtonBaseCommandSource |
NButtonBase |
A command source that can be applied to all types of buttons that derive from NButtonBase.
It subscribes for the NButtonBase-Click event to execute the command with empty parameter. |
NToggleButtonCommandSource |
NToggleButton |
A command source that can be applied to all types of buttons that derive from NToggleButton.
It subsrcibes for the NButtonBase.Click event to execute the action and also updates the Checked state of the owner toggle button. |
Menu Items
|
NMenuItemCommandSource |
NMenuItem |
A command source that can be applied to NMenuItem instances.
It subsrcibes for the NMenuItem-Click event to execute the command with empty parameter. |
NCheckableMenuItemCommandSource |
NCheckableMenuItem |
Executes the action when the menu item is clicked. Also updates the menu item checked state from the action checked state. |
Style Split Buttons
|
NFillSplitButtonCommandSource
NStrokeSplitButtonCommandSource
NShadowSplitButtonCommandSource
|
NFillSplitButton
NStrokeSplitButton
NShadowSplitButton |
Style split buttons execute the command when the style split button selected value has changed or the action button is clicked.
In both cases the selected value is passed as argument. If the selected value Automatic property is true, the command argument is set to NNode.ClearValueObject. |
Misc
|
NComboBoxCommandSource |
NComboBox |
Subscribes for the NComboBox-SelectedIndexChanged event to execute the command with a parameter equal to selected combo box item index. |
NLabelCommandSource |
NLabel |
The text of the label is updated from the command active parameter. |
See Also