Silverlight supports the concept of a routed event for several input events that are defined in base classes and are present on most UI elements that support user interaction and input:
A routed event is an event that is potentially passed on (routed) from a child object to each of its successive parent objects in the object tree. The object tree in question is approximated by the XAML structure of your UI, with the root of that tree being the root element in XAML. The true object tree might vary somewhat from the XAML because the object tree does not include XAML language features such as property element tags, but in general you can think of the routed events as "bubbling" from XAML object element children that raise the event, towards the parent object element that contains them, and continuing to route until the root element is reached. (If you have used certain Web technologies such as DHTML before, the "bubbling" concept might already be familiar to you.)
Note: |
|---|
WPF supports an analogous "tunneling" routing strategy, whereby the root of a page / object tree has the first chance to handle a routed event, and the event then "tunnels" down the object tree toward its event source. Silverlight does not use "tunneling" routed events. Events in Silverlight either follow the "bubbling" routing strategy (and are referred to as routed events) or do not route at all. There are also other API-level differences in routed event behavior between Silverlight and WPF. |
The OriginalSource Property of RoutedEventArgs
When an event bubbles up an event route, sender is no longer the same object as the event-raising object. Instead, sender is the object where the handler that is being invoked is attached. In many cases, sender is not the object of interest, and you are instead interested in knowing information such as which of the possible child objects the mouse is over, or which object held focus when a keyboard key was pressed. For these cases, the value of the OriginalSource property is the object of interest.
At all points on the route, OriginalSource reports the original object that raised the event, rather than where the handler is attached For an example scenario where this is useful, consider an application where you want certain key combinations to be "hot keys" or accelerators, regardless of which control currently holds keyboard focus and initiated the event. In terms of the object tree, the focused object might be nested within some items list in a list box, or could be one of hundreds of objects in the overall UI. Having to attach handlers to every possible focusable object in an application to detect your accelerator is obviously impractical. But because the keyboard events are bubbling routed events, the event eventually reaches the root object in its route. Therefore, you can often attach a single KeyDown handler on the root object and rely on the behavior that a KeyDown event eventually bubbles to the root object. Then the handler can determine whether that key is the valid combination for an intended accelerator action, or whether no action is necessary.
Tip: |
|---|
Using input bubbling to your advantage is particularly useful if you are creating a templatable control, in which case you do not even always have the opportunity to define the handlers for the template parts because your control has potentially been user-retemplated. |
The Handled Property
Several event data classes for specific routed events contain a property named Handled. For examples, see MouseButtonEventArgs..::.Handled, KeyEventArgs..::.Handled, MouseWheelEventArgs..::.Handled, and ValidationErrorEventArgs..::.Handled. Handled is a settable Boolean property.
Setting the Handled property to true influences the event system in Silverlight. When you set the value to true in event data, the routing stops for purposes of most event handlers; the event does not continue along the route to notify other attached handlers of that particular event case. What "handled" as an action means in the context of the event and how your application responds, is entirely up to you. However, you should definitely be aware of this behavior of the Silverlight event system when you choose to set Handled in your event handlers.
Not all of the routed events are cancellable in this way. GotFocus, LostFocus, and MouseMove will always route all the way to the root, and their event data classes do not have a Handled property that can influence that behavior. Therefore, checking OriginalSource values for those events is often a good idea, to make sure you are not handling an event and making incorrect assumptions about what the event means and how it was sourced.
Note: |
|---|
The concept of a Handled property for routed events also exists in WPF. In WPF, the Handled property exists on all routed event-data classes; in Silverlight only the specific event data classes that have their own Handled property can be used to cancel the related event's route. |
Routed Events Outside the Visual Tree
Certain objects in Silverlight participate in a relationship with the primary visual tree that is conceptually like an overlay over the main visuals, and are not part of the usual parent-child relationships that connects all tree elements to the visual root. This is the case for any displayed Popup or ToolTip. If you want to handle routed events from a Popup or ToolTip, you should place the handlers on specific UI elements that are within the Popup or ToolTip and not the Popup or ToolTip elements themselves, and you should not rely on routing inside any compositing that is done for Popup or ToolTip content. This is because event routing for routed events works only along the main visual tree. Popup or ToolTip are not considered parents of subsidiary UI elements, and never receive the routed event, even if are trying to use something like the Popup default background as the capture area for input events.