When you handle an element’s event in XAML, the event handling method you specify must exist in the class contained in the associated code-behind file. That’s fine for most situations, but what about when you want that element’s event(s) to be handled by another class? In the first version of WPF there is no support for declaratively handling events with methods in arbitrary classes. This blog post shows a way around that limitation.
I created a utility class named RoutedEventManager which exposes an attached property named HandlerInfo. That property is of type RoutedEventHandlerInfo; a class which stores the information needed for this technique to work. Here is an example of those classes in use. The XAML seen below shows a Button in a Window. The Button’s Loaded event is handled by a utility class named ButtonHelper.
As seen in that XAML snippet, the Button’s Loaded event is not directly assigned a handler. The HandlerInfo attached property is set to an instance of RoutedEventHandlerInfo, specifying the information needed to eventually assign a handler to the Loaded event. Here is the method which handles the Button’s Loaded event, in the ButtonHelper class:
The implementation details of ButtonHelper are unimportant, but it is worth pointing out why it handles the Button’s Loaded event. An attached property can only be set on an element once. In the demo app we need to handle three of the Button’s events (Click, MouseEnter, and MouseLeave), so we assign handlers to those events in the method which handles Loaded. If you only need to handle one event “externally” on the element, say the Click event, this extra step is unnecessary. In that case you could just establish a handler for the Click event with RoutedEventManager in XAML.
We will not delve too deep into how this works, but free feel to explore the code in the demo app at the end of this post. For those of you with insatiable curiosity and no time to poke around in a demo project, here is the basic gist. When the HandlerInfo attached property is set on an element, eventually this method in RoutedEventManager is invoked:
That method depends on the CreateHandler method of the RoutedEventHandlerInfo class, which is implemented like this:
As of this writing you can only specify a static method as the event handling method. I’m considering whether it would be helpful to be able to specify an instance method on a particular object. If you have a compelling reason for that feature to exist, please let me know.
These classes are not “done yet.” I’m still pondering what other functionality might be useful for them, so feel free to drop me a comment if you have a neat idea.
Download the demo app here: RoutedEventManager (demo project) Be sure to change the file extension from .DOC to .ZIP and then decompress it.