Let’s say you have a simple application that looks as follows:
When you hover over the Log-In button, which elements do you think receive notification of something happening?
One of the elements that gets notified is the button, as you would expect. What you may not realize is that the event propagates beyond the button and to other elements in its visual tree such as its parent, its parent’s parent, and so on.
That roundabout way of having events routed through the parents is what makes events in WPF and Silverlight known as routed events.
Let’s look at an example of a simple application broken down into its visual tree:
The application portrayed is fairly simple. It contains a Button and Label (aka TextBlock in Silverlight) control nested inside a Grid control which, in turn, is hosted by our overall Window/UserControl control. When you hover over your button, since the hover is a routed event, your MouseEnter event gets recognized by your Grid and Window/UserControl controls.
Peers are not affected. You interacting with your Button will have no affect on the Label control that is your peer. This is true even if your Label is overlapping your button. Since your Label/TextBlock is never hovered over and it is a peer of your button, it doesn’t partake in this event handling festivity!
Routing Strategies: Bubbling, Tunneling, and Direct
While I mentioned that your events get recognized by the parents, the order by which they get recognized depends on the routing strategy used. The two most popular routing strategies are bubbling and tunneling.
In a bubbling strategy, you start with the control that originated the event and traverse up the tree:
This is what I described earlier where the order of the elements that get notified by an event on the button goes from Button to Grid to Window. The tunneling strategy works in the opposite way.
With tunneling, when an event is fired, you go all the way to the root and traverse down until you hit the control that originated the event:
In WPF, you can specify which routing strategy to use based on the type of event you are listening for. If you look at the list of events your element supports, if it has the word “Preview” in front of it such as PreviewMouseLeftButtonDown, you are dealing with a tunneling event:
[ example of tunneling events ]
For most of the other events that do not have Preview in front of them, you are dealing with bubbling events.
Silverlight only supports bubbling, so you will always have events that move up to the root as opposed to starting with the root and moving down.
Tunneling and bubbling events processing sequence
UIElement class defines many routed events for keyboard, mouse, and stylus input. Most of these are bubbling events, but many of them are paired with a tunneling event. Tunneling events can be easily identified because, by convention, they are named with a
Previewprefix. These events, also by convention, are raised immediately before their bubbling counterpart. For example,
PreviewMouseMove is a tunneling event raised before the
MouseMove bubbling event.
The idea behind having a pair of events for various activities is to give elements a chance to effectively cancel or otherwise modify an event that’s about to occur. By convention, WPF’s built-in elements only take action in response to a bubbling event (when a bubbling and tunneling pair is defined), ensuring that the tunneling event lives up to its “”preview” name. For example, imagine you want to implement a
TextBox that restricts its input to a certain pattern or regular expression (such as a phone number or zip code). If you handle
KeyDown event, the best you can do is remove text that has already been displayed inside the
TextBox. But if you handle
PreviewKeyDown event instead, you can mark it as “handled” to not only stop the tunneling but also stop the bubbling
KeyDown event from being raised. In this case, the
TextBox will never receive the
KeyDown notification and the current character will not get displayed
Where is the event for handling the pressing of a mouse’s middle button?
If you browse through the various mouse events exposed by
ContentElement, you’ll find events for
MouseRightButtonUp (as well as the tunneling
Preview version of each event). But what about the additional buttons present on some mice?
This information can be retrieved via the more generic
MouseUp events (which also have
Preview counterparts). The arguments passed to such event handlers include a
MouseButton enumeration that indicates which button’s state just changed:
XButton2. A corresponding
MouseButtonStateenumeration indicates whether that button is