Intersoft ClientUI 8 > ClientUI Fundamentals > Commanding Overview |
ClientUI Framework provides a powerful commanding framework that enables developers to leverage the commanding pattern to use in their applications. The commanding framework in ClientUI supports the routed command concept available in WPF, as well as several advanced command types which will be discussed later in this topic.
To learn more about the concepts and frameworks available in ClientUI, see ClientUI Architecture Overview.
This overview describes the basic concepts of commanding, its benefits, how to use it and why you should use commands in your application whenever possible.
This topic contains the following sections:
Command is mainly used to separate the semantics and the object that invokes a command from the logic that executes the command. This allows for multiple and disparate sources to invoke the same command logic, and it allows the command logic to be customized for different targets.
The simplest form of a Command is an object that implements ICommand, which exposes CanExecute and Execute method. The command is then consumed in an application which provides a consistent pattern to query and execute the logic associated to the Command. This pattern is often referred as Commanding Pattern which has been around for a while.
With the advent of Windows Presentation Foundation (WPF), the commanding pattern has evolved into more advanced commands such as routed command and routed UI command, which take advantage of the robust visual tree model. The routed command model uses the event routing mechanism to notify the visual tree about the command being executed. For more information about event routing, see Routed Events Overview.
Developers find routed command to be more intuitive and easier to implement because a routed command can be generally consumed in various ways, either declaratively defined in the XAML or programmatically implemented using code.
Although Silverlight was designed as a subset of WPF, it does not ship with the routed command infrastructure. ClientUI addresses the lacking of commanding support in Silverlight by implementing complete routed command infrastructure according to the specification and behaviors in the WPF. The commanding support in ClientUI will be discussed later in this topic. |
The routed command model can be summarized into four main concepts: the command, the command source, the command target, and the command binding:
The command is the action to be executed.
The command source is the object which invokes the command.
The command target is the object that the command is being executed on.
The command binding is the object which maps the command logic to the command.
A routed command is typically implemented through these processes: a RoutedCommand is initially associated to a control that implements ICommandSource such as UXButton, create a CommandBinding, and then create the event handlers which implement the logic for the RoutedCommand.
The following code example illustrates the big picture of these processes and shows how the routed command and command binding can be easily defined in XAML.
XAML |
Copy Code
|
---|---|
<Grid x:Name="LayoutRoot"> <Intersoft:CommandManager.CommandBindings> <Intersoft:CommandBindingCollection> <Intersoft:CommandBinding Command="Commands:EditingCommands.Cut" CanExecute="CutCmdCanExecute" Executed="CutExecuted"/> </Intersoft:CommandBindingCollection> </Intersoft:CommandManager.CommandBindings> <Intersoft:DockPanel Name="dockPanel1" FillChildMode="Custom"> <Intersoft:UXToolBar Name="toolBar1" Intersoft:DockPanel.Dock="Top"> <Intersoft:UXToolBarButton Name="btn_Cut" Command="Commands:EditingCommands.Cut" DisplayMode="Image" Icon="../Images/CutHS.png" ToolTipService.ToolTip="Cut"/> </Intersoft:UXToolBar> <Intersoft:UXTextBox Name="textBox1" Text="Type your text here..." Intersoft:DockPanel.IsFillElement="True" /> </Intersoft:DockPanel> </Grid> |
The following code example shows the event handler for the CanExecute and Executed routed event for the CommandBinding associated to the Cut command.
C# |
Copy Code
|
---|---|
private void CutCmdCanExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = true; } private void CutExecuted(object sender, ExecutedRoutedEventArgs e) { string command = ((RoutedCommand)e.Command).Name; string target = ((FrameworkElement)e.OriginalSource).Name; MessageBox.Show("The " + command + " command has been invoked on target object " + target); } |
For a complete example of how to implement a RoutedCommand, see How-to: Implement a RoutedCommand.
To see more walkthrough and examples of commanding, see Commanding How-to Topics.
The commanding pattern, specifically the routed command model, provides solid infrastructure and flexible ways for developers to create consistent and reliable user experiences. Consequently, you should consider using commands in your application design whenever possible.
There are several advantages to use the commanding pattern in your application:
Despite being a subset of WPF, Silverlight does not include routed command infrastructure in its core framework. Consequently, developers would not be able to build a rich user interface using the commanding pattern that similar to the WPF commanding. ClientUI provides developers with a comprehensive framework that implements a full specification of routed command infrastructure.
The following sections describe an overview of the commanding support in ClientUI.
ClientUI provides a full set of class libraries that implement routed command according to the specification, mechanism and behaviors of WPF routed command. Some major libraries include CommandManager, CommandBinding, InputBinding, InputGesture, ICommandSource and a number of types to support the routed command infrastructure.
In addition, ClientUI also supports the tunneling version of the commanding routed events such as the PreviewCanExecute and PreviewExecuted, in addition to the CanExecute and Executed bubbling routed events. To learn more about routed events, see Routed Events Overview.
With ClientUI commanding framework, you can build application using unified XAML and code that target both Silverlight and WPF platform. For more information about unified development model with ClientUI, see Unified Development Model.
For the routed command model to work efficiently, there must be user interface controls that implement ICommandSource interface to support and take advantage of the routed command. Because the routed command infrastructure is built into the ClientUI's framework, many of the command-nature controls such as UXButton, UXToolbarButton, UXSplitButton, UXHyperlinkButton, UXMenuItem and more, implement the ICommandSource interface enabling you to fully leverage the benefits of routed command.
Specifically, the ClientUI controls that implement ICommandSource interface, which are generally referred as command sources, exposes the members listed in the following:
ClientUI makes use of commanding extensively throughout its frameworks and user interface controls to create rich feature-sets that designed with commanding semantics. Features that use commanding semantics provides more flexible ways for developers to consume the feature and at the same time delivers more solid design that allows better scalability and easier to extend.
In addition, controls that are built with commanding semantics use loosely-coupled engineering that separates the actual logic implementation from the feature. Consequently, this allows a particular feature to be easily reused and consumed in ways that are not possible in traditional controls that do not leverage the commanding pattern.
The examples of frameworks in ClientUI that make use of commanding extensively are navigation framework and application framework. Several advanced controls like UXWindow, UXDesktop and UXDesktopDock make use of commanding extensively to create user experience that works consistently across the user interface elements. For example, when a window cannot be closed, the Close button in the title bar, the Close menu item in the context menu, and the Close feature in the task bar will be grayed out.
As the result of the comprehensive support for commanding, ClientUI includes a number of predefined command library that you can use directly, such as the BrowseBack, BrowseForward and Navigate for navigation commands and SetActive, Maximize, Close and more for windowing commands. The complete list of the predefined command library is described later in this topic.
The routed command model introduced in WPF basically provides an automatic state synchronization between the command sources and the command through command binding. In WPF, the command source supports the IsEnabled synchronization based on the value of the CanExecute in the event data.
ClientUI extends the routed command model further by introducing hybrid routed command, a more advanced routed command that supports two kind of state synchronization behavior. In addition to the IsEnabled handling, HybridRoutedCommand can automatically synchronize the Visibility property of the command sources based on the value of the CanExecute in the event data. More details about HybridRoutedCommand, see Hybrid Commands.
There are a number of ways to implement routed command in your application. You can work with the commands in XAML, or register them using code. Depending on your requirements, you can use instance command handler or class command handler, which both of them are supported in the ClientUI commanding framework.
The following example shows how to setup the Cut button to execute the EditingCommands.Cut routed command when the button is clicked.
XAML |
Copy Code
|
---|---|
<Grid x:Name="LayoutRoot"> <Intersoft:CommandManager.CommandBindings> <Intersoft:CommandBindingCollection> <Intersoft:CommandBinding Command="Commands:EditingCommands.Cut" CanExecute="CutCmdCanExecute" Executed="CutExecuted"/> </Intersoft:CommandBindingCollection> </Intersoft:CommandManager.CommandBindings> <Intersoft:DockPanel Name="dockPanel1" FillChildMode="Custom"> <Intersoft:UXToolBar Name="toolBar1" Intersoft:DockPanel.Dock="Top"> <Intersoft:UXToolBarButton Name="btn_Cut" Command="Commands:EditingCommands.Cut" DisplayMode="Image" Icon="../Images/CutHS.png" ToolTipService.ToolTip="Cut"/> </Intersoft:UXToolBar> <Intersoft:UXTextBox Name="textBox1" Text="Type your text here..." Intersoft:DockPanel.IsFillElement="True" /> </Intersoft:DockPanel> </Grid> |
The following code example shows the event handler for the CanExecute and Executed routed event for the CommandBinding associated to the Cut command.
C# |
Copy Code
|
---|---|
private void CutCmdCanExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = true; } private void CutExecuted(object sender, ExecutedRoutedEventArgs e) { string command = ((RoutedCommand)e.Command).Name; string target = ((FrameworkElement)e.OriginalSource).Name; MessageBox.Show("The " + command + " command has been invoked on target object " + target); } |
Similar to the objective in the previous example, the following example shows how to setup the routed command and binding using code.
XAML |
Copy Code
|
---|---|
<Grid x:Name="LayoutRoot"> <Intersoft:DockPanel Name="dockPanel1" FillChildMode="Custom"> <Intersoft:UXToolBar Name="toolBar1" Intersoft:DockPanel.Dock="Top"> <Intersoft:UXToolBarButton Name="btn_Cut" Command="Commands:EditingCommands.Cut" DisplayMode="Image" Icon="../Images/CutHS.png" ToolTipService.ToolTip="Cut"/> </Intersoft:UXToolBar> <Intersoft:UXTextBox Name="textBox1" Text="Type your text here..." Intersoft:DockPanel.IsFillElement="True" /> </Intersoft:DockPanel> </Grid> |
C# |
Copy Code
|
---|---|
private void CommandBindingCode_Loaded(object sender, RoutedEventArgs e) { // Create a CommandBinding and attaching an Executed and CanExecute handler CommandBinding cutCommandBinding = new CommandBinding( EditingCommands.Cut, CutExecuted, CutCmdCanExecute); // Create the CommandBindingCollection to hold the command binding CommandBindingCollection bindingCollection = new CommandBindingCollection(); bindingCollection.Add(cutCommandBinding); // Set the binding collection to the layout root CommandManager.SetCommandBindings(this.LayoutRoot, bindingCollection); } private void CutCmdCanExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = true; } private void CutExecuted(object sender, ExecutedRoutedEventArgs e) { string command = ((RoutedCommand)e.Command).Name; string target = ((FrameworkElement)e.OriginalSource).Name; MessageBox.Show("The " + command + " command has been invoked on target object " + target); } |
In addition to instance command binding, the commanding framework in ClientUI also supports class command binding API which is available in the CommandManager class. The class command binding is particularly useful when you have a fairly large amount of commands to bind to the controls.
The following example shows how to use the RegisterClassCommandBinding method to register the command binding to a specific class.
C# |
Copy Code
|
---|---|
static ClassCommandBinding() { RoutedUICommand[] commands = new RoutedUICommand[] { EditingCommands.Cut, EditingCommands.Copy, EditingCommands.Paste }; // register class-level command binding for RoutedUICommand foreach (RoutedUICommand command in commands) { CommandManager.RegisterClassCommandBinding( typeof(UXPage), new CommandBinding(command, OnCommandExecuted, OnCanExecute)); } } private static void OnCanExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = true; } private static void OnCommandExecuted(object sender, ExecutedRoutedEventArgs e) { string command = ((RoutedCommand)e.Command).Name; string target = ((FrameworkElement)e.OriginalSource).Name; MessageBox.Show("The " + command + " command has been invoked on target object " + target); } |
The class command binding registration is typically initialized in the static constructor of the class to ensure that class command binding is not initialized multiple times. Registering the class command binding incorrectly would result in undesirable effect. |
For more advanced examples of using the commanding framework, see Commanding How-to Topics.
ClientUI makes use of commanding extensively throughout its frameworks and user interface controls to create rich feature-sets that designed with commanding semantics. Several key frameworks in ClientUI that make use of commanding extensively are navigation framework and application framework. Several advanced controls like UXWindow, UXDesktop and UXDesktopDock make use of commanding extensively to create user experience that works consistently across the user interface elements. For example, when a window cannot be closed, the Close button in the title bar, the Close menu item in the context menu, and the Close feature in the task bar will be grayed out.
ClientUI includes a number of predefined command library that you can use directly such as described in the following list.
Navigation Commands:
Window Commands:
For full details about the navigation and window commands, see Navigation Overview and Window and Dialog Boxes Overview respectively.
In addition to the full support for routed command model, ClientUI extends its commanding framework further to support MVVM pattern without trading off the benefits of routed command model.
Specifically, ClientUI provides DelegateCommand, a specialized command object that can be used to handle a delegate directly in the view model, and still can be bound to the view through binding. To learn more about using commanding with MVVM pattern, see MVVM Pattern Overview.