WPF the routed event and routed command

The topic originate/induce/beget/engender from the discussion of the DelegateCommand vs RoutedCommand. However, there are a grand topic covering with first the routed event.

 

Below is transcribed from the blog that is available WPF Routed Commands: Overview and Exampels ;

 

And it has several external links which you can find here: 

 

http://msdn.microsoft.com/en-us/library/ms752308.aspx
http://msdn.microsoft.com/en-us/magazine/cc785480.aspx
http://msdn.microsoft.com/en-us/library/ff650631.aspx

 

The following are copied from the WPF Routed Commands: Overview and Exampels, some more example will be provided later to better illustrate the idea.

 

 

WPF Routed Commands: Overview and Examples

This article focuses on such WPF capability as routed commands, their structure and ways of using them. Apart from this, here we will describe benefits for the developer who use routed commands and problems that the developer can encounter.

WPF-routed commands give you a specific mechanism for hooking up UI controls such as toolbar buttons and menu items to handlers without introducing a lot of tight coupling and repetitive code into your application. The difference is that, contrary to an ordinary handler hooked up to a button or timer, the routed command separates the semantics and the object that invokes a command from the logic that executes the command. Routed commands give you three main things on top of normal event handling:

  • Routed command source elements (invokers) can be decoupled from command targets (handlers)—they do not need direct references to one another, as they would if they were linked by an event handler.
  • Routed commands will automatically enable or disable all associated UI controls when the handler indicates the command is disabled.
  • Routed commands allow you to associate keyboard shortcuts and other forms of input gestures as another way to invoke the command.

Four Main Concepts of WPF Commanding

The routed command model in WPF can be broken up into four main concepts:

  • Command — the action to be executed
  • Command source — the object which invokes the command
  • Command target — the object that the command is being executed on
  • Command binding — the object which maps the command logic to the command

Command

WPF commands are custom implementations of the ICommand interface. ICommand has the Execute and CanExecute methods and the CanExecuteChanged event. Execute performs the execution logic of the command. CanExecute determines if the command can be executed for the current command target. If true value was returned, command can be executes and method Execute() is called. Method gradually calls for paired events PreviewExecuted and Executed as tasks to complete command in all target elements using binding elements.  The CanExecuteChanged event is raised if the command manager that centralizes the commanding operations detects a change in the command source that might invalidate a command that has been raised but not yet executed by the command binding.

public interface ICommand
{
event EventHandler CanExecuteChanged;
bool CanExecute(object parameter);
void Execute(object parameter);
}

The Execute and CanExecute methods of the RoutedCommand class do not contain the application logic for the command, but rather they raise routed events that tunnel and bubble through the element tree until they encounter an object with a CommandBinding. The CommandBinding contains the handlers for these events and it is the handlers that perform the command.

WPF supplies a set of common routed commands spread across several classes: MediaCommands, ApplicationCommands, NavigationCommands, ComponentCommands and EditingCommands. The classes include only the RoutedCommand objects but not the implementation logic of the command. The implementation logic is the responsibility of the object on which the command is being executed on.

Command Source

A command source is the object which invokes the command. Command sources in WPF generally implement the ICommandSource interface.
ICommandSource exposes three properties: Command, CommandTarget and CommandParameter. Command is the command to execute when the command source is invoked. CommandTarget is the object on which to execute the command. If the CommandTarget is not set, the element with keyboard focus will be the command target. CommandParameter is a user-defined data type used to pass information to the handlers implementing the command.

public interface ICommandSource
{
ICommand Command { get; }
object CommandParameter { get; }
IInputElement CommandTarget { get; }
}

Typically, a command source will listen to the CanExecuteChanged event. This event informs the command source that the ability of the command to execute on the current command target may have changed. The command source can query the current status of the routed command by using the CanExecute method. The command source can then disable itself if the command cannot execute. An example of this is a MenuItem graying itself out when a command cannot execute.

The WPF classes that implement the ICommandSource are ButtonBase, MenuItem, Hyperlink and InputBinding.

In order for an object as a command to act as a command source, it must be associated with a command. There are a few ways to accomplish this. One way is to use InputBinding.

Another way is to add the KeyGesture object to the InputGestureCollection collection of the RoutedCommand object.

Example
KeyGesture openCommandKeyGesture = new KeyGesture(Key.O,
ModifierKeys.Control);

//Alternative 1
KeyBinding openCmdKeybinding = new KeyBinding(ApplicationCommands.Open,
openCommandKeyGesture);
InputBindings.Add(openCmdKeybinding);
//Alternative 2
ApplicationCommands.Open.InputGestures.Add(openCommandKeyGesture);

KeyGesture is a class that defines a keyboard combination that can be used to invoke a command. KeyGesture is a class that defines a keyboard combination that can be used to invoke a command. The same way MouseGesture class could be used.

Command Target

The command target is the element on which the command is executed. WPF elements inherit from the System.Windows.UIElement class, which has property-collection CommandBindings of CommandBindingCollection type.  This helps to make this element listening for the team. With regards to a RoutedCommand the command target is the element at which routing of the  Executed and CanExecute starts. If the CommandTarget is set on an ICommandSource and the corresponding command is not a RoutedCommand,  the command target is ignored.

When command calls linked to it command object the last consequently executes CanExecute() и Execute()methods of ICommand interface. These methods generate command events that move through tree of elements checking their   CommandBindings collections in order to identify CommandBinding object relevant to called command. When this binding element will be identified in listening element signed for the event Executed handler will be immediately executed.

The command source can explicitly set the command target. If the command target is not defined, the element with keyboard focus will be used as the command target. One of the benefits of using the element with keyboard focus as the command target is that it allows the application developer to use the same command source to invoke a command on multiple targets without having to keep track of the command target.

For example, if a MenuItem invokes the Paste command in an application that has a TextBox control and a PasswordBox, control, the target can be either depending on which control has keyboard focus. The TextBox and PasswordBox class implementations have a built-in command binding for the Cut command and encapsulate the clipboard handling for that command (and Copy and Paste as well). The active command handler is determined by a combination of where the command invoker and command handler are in the visual tree, and where the focus is in the UI. Usually, a command invoker looks for a command binding between its own location in the visual tree and the root of the visual tree. If it finds one, the bound command handler will determine whether the command is enabled and will be called when the command is invoked. If the command is hooked up to a control inside a toolbar or menu (or, more generally, a container that sets FocusManager.IsFocusScope = true), then some additional logic runs that also looks along the visual tree path from the root to the focus element for a command binding.

The following example shows how to explicitly set the command target in markup and in code behind.

Example

CommandTarget="{Binding ElementName=mainTextBox}" />

Command Binding

A CommandBinding object associates a command with the event handlers that implement the command. The CommandBinding contains a Command property, and PreviewExecuted, Executed, PreviewCanExecute and CanExecute events.

Command is the command that the CommandBinding is being associated with. The event handlers which are attached to the PreviewExecuted and Executed events implement the command logic. The event handlers attached to the PreviewCanExecute and CanExecute events determine if the command can execute on the current command target.

Each element of logical tree can be set as listening. But to get more flexibility of command binding in could be recommended to add root element for example into window.

The following example shows how to create a CommandBinding on the root Window of an application:

Example:

CanExecute="CommandBinding_CanExecute" 
Executed="CommandBinding_Executed" />

Routed Commands: Problems and Solutions

Routed commands work nicely for simple user interface scenarios, hooking up toolbar and menu items, and handling those things that are inherently coupled to the keyboard focus (such as clipboard operations). Where routed commands are insufficient, however, is when you start building complex user interfaces, where your command handling logic is in supporting code for your view definitions and your command invokers are not always inside of a toolbar or menu.

The problem when you get into that arena is that the enabling and handling logic for a command may not be part of the visual tree directly; rather, it may be located in a presenter or presentation model. Additionally, the state that determines whether the command should be enabled may have no relation to where the command invokers and views are in the visual tree. You may also have scenarios where more than one handler is valid at a given time for a particular command.

To avoid problems related to visual tree location when working with routed commands, you should try to be simple. Usually, you need to be sure that handlers for a command are in the same element or higher in the tree then an element that is calling the command.

Conclusion

To sum up, today few developers are using routed commands on a daily basis. To me, the reasons are both the lack of awareness and experience in the developer community and problems that we encounter when developing complex GUIs. However, WPF routed commands are still an elegant way to link GUL controls to handlers, and often they can help you greatly.

Denis Glazkov, Software Developer, Digital Design

For preparing this article following materials were used:
http://msdn.microsoft.com/en-us/library/ms752308.aspx
http://msdn.microsoft.com/en-us/magazine/cc785480.aspx
http://msdn.microsoft.com/en-us/library/ff650631.aspx

 

 

 

你可能感兴趣的:(WPF)