Routed events are a new event system built explicitly for WPF. This tutorial examines the routed event system and shows how the event can bubble up or tunnel down the visual tree. Learn about the attached event concept too.
- [Instructor] It's important to point out that routed events are based on .NET events. They are built on top of the .NET model and extend it in several significant ways. Therefore, much of what you know about .NET events is applicable to WPF routed events. They were created to enhance the way events work, especially in a UI system that relies on a hierarchical representation of managed objects. And, they solve some problems in the old event model. Here's an example of a problem that existed before routed events.
I have a button that contains many nested child elements. I want to respond to a mouse event, say, a mouse down event, or MouseMove event. In the old model, I'd need to subscribe to the event at every level. I'd need to register a MouseMove handler for the button, border, stack panel, image, and text block elements. If I alter the UI, by adding another text block to the button, then I have to be sure and add another event subscription for the new element.
And it gets more complicated in WPF, due to the idea of control templates. Templates provide a way to specify an alternative UI for a UI control. When the control is rendered to the screen, the default UI template is replaced with the new UI template. This is a powerful WPF technique, but imagine if the UI designer that created the template had to remember to create event handlers for every element in the replacement template. Routed events solve this problem, and many others.
In order to make a routed event, it has to be registered with the WPF class. This is more complex than adding a .NET event to a class. Basically, it involves writing code to register the event with the WPF system. This is similar to the way dependency properties are registered. Because the WPF system knows about the routed event, it can provide services to the event that you don't get with .NET events. To be clear, in most cases you won't need to register your own routed events unless you're creating custom WPF controls.
You'll use the events and consuming them is easy. One of the services provided to routed events by the WPF system is routing. That means that an event can traverse the tree of UI elements. Which direction the event moves is based on the choice made when registering the event. This is known as the routing strategy, but you can also think of it as the routing direction. There are three choices available: bubble, tunnel, and direct. I'll discuss the bubble and tunnel in this course.
The bubble direction means that the event can travel up the tree from child element to parent. One example from WPF is the MouseMove event. This event fires every time the mouse moves over a visual element on the screen. When I subscribe to the MouseMove event in the image element, I get notified when the movement is detected over the image, but not over any of the other elements in the tree. When I subscribe to the MouseMovement at the stack panel element, I get notified when the mouse moves over the image, the text block, and the stack panel.
I can subscribe to the event at any element on the tree, as long as that element supports that event. By subscribing at the top element, in this case, the grid element, I can write one handler that deals with all the child elements. Later, if I add another child element to the stack panel, say, adding a second image, my code still works, because the subscription is at the grid level. The tunnel direction means the event can travel down the tree, from parent element to children. One example from WPF is the PreviewMouse event.
This event fires just before the MouseMove event. You can think of it as an associated event, or paired event, with the MouseMove event. Typically, preview events, the default name for events using the tunnel direction, exist for validating conditions prior to the associated event. Then, if necessary, I can stop the associated event from happening. If there is a tunneling and bubbling event pair, the tunnel event always fires first, followed by the bubble event. In this example, I can preview the event at the parent level.
Or, I can subscribe to the event at the child level. Since there are no handlers at the parent level, it moves down the tree until it reaches the TextBlock, and my code runs. Another feature of the WPF routed event system is the concept of attached events. This allows you to subscribe to an event at the parent level. The main difference is that you can include events that are not part of the parent class definition. For example, let's look at the Checked event. This event fires when the user checks a checkbox control.
The checked event is part of the checkbox members, but the other elements in this tree, grid, border, and stack panel, don't have a checked event. With the attached property syntax, I can subscribe to the checked event at the grid level, or any of the other parent elements. The event bubbles up the tree from the checkbox children and I react to the event in one central location. Later, when I add another checkbox to the UI, I don't need to add another subscriber to my application.
To conclude, the WPF team thought long and hard about how to implement a better event system for their xaml-based, hierarchical, managed type UI system. They devised a system that provides helpful services for events. In addition to the services I mentioned, like event routing and attached events, WPF ensures that events are more memory-efficient when working in complex UI scenarios. Routed events are the foundation of the event system in WPF. Be aware, there are other parts of WPF that build on top of routed events, or provide event-like features.
I'm talking about triggers, event setters, commands, and behaviors. I won't discuss these concepts in the course, but they are a fascinating part of WPF that deserves future study.
- Understanding routed events and event signatures
- Wiring up event handlers
- Event bubbling and tunneling
- Programming mouse events
- Programming keyboard and ink events