Just about to land on master is an update to the Perspex eventing system. Perspex generally follows WPF quite closely in its eventing, using a routed event model, but this update marks a few deviations away from that of WPF.
The main features of WPF’s routed events are:
- Direct events that work pretty much the same as standard .NET events in that they fire only on the control that the event was raised on.
- Tunneling events (
Preview*events in WPF) which start at the root and tunnel their way up to the control that the event was raised on.
- Bubbling events which start at the control that the event was raised on and bubble their way up to the root.
- Class handlers which are called before the standard event handlers to invoke the
On*virtual methods in the control classes themselves.
I’ve recently been diving into Windows Store Apps (aka XAML apps, or WinRT apps, or Metro apps - MS
need to get their naming shit together) and noticed that there, tunneling events are done away with
entirely. This is in some ways a good idea - the
Preview* events cluttered up class definitions
and intellisense with a load of stuff that must users will never be interested in, but at the same
time as a control author they can be very useful. And they meant that for every event that wants to
be both bubbling and tunneling, you have to declare and call the pair.
In Perspex I’ve not gone as far as WinRT (lets just call it WinRT for brevity) and removed them
completely, however they are somewhat hidden in that there are no longer any
So lets have a look at how things work in Perspex.
Direct Events, Bubbling Events and Class Handers
Direct events (such as
Button.Click) and bubbling events (such as
KeyDown) are still available
in the usual manner - there’s generally a standard event exposed on the class (i.e.
Control.KeyDown) to be used by users of the control, together with an
On* virtual method in the
class (such as
Control.OnKeyDown) to be used by control authors.
The virtual methods are called by registering a class handler which in WPF looked something like this:
However, in Perspex we can make use of modern C# to make that a little easier.
Much nicer! You can pass a RoutingStrategy to that call to AddClassHandler if you want to handle tunneling events: by default it will handle direct and bubbling events.
As mentioned earlier there are no longer any
Preview* tunneling events exposed on Perspex
controls. That’s not to say you couldn’t add some to your own controls, but as they’re used by a
tiny subset of users, they kept out of the way by default. To subscribe to a tunneling event
you need to call
The AddHandler method returns an IDisposable which you can use to end the subscription, or you can
Events are registered more or less the same as they are in WPF, but instead of registering a pair
RoutedEvents when you want both a bubbling and tunneling event, you only have to register one.
RoutedEvents can be strongly typed:
Events are raised using the
Marking Events Handled
As in WPF, you can mark an event handled to stop its propagation by setting the
RoutedEventArgs.Handled property to
true. You should do this if you have “acted” on the event,
i.e. your button has been clicked so you don’t want your parent control to also act on that click.
So what if you want to also handle events that have been marked handled? You just need to pass an extra argument to AddHandler the same as you would in WPF:
What if you want to handle both tunneling and bubbling events, you… you… weirdo? Well you can do that: