Dutton

Handling events from within a ControlTemplate in WPF

Here's an interesting one that had me stumped for a few hours.

Following on from my previous post, where I explained how to create a ControlTemplate to style a TextBox in WPF, I've got an object, TextEntryBox, which dervies from a TextBox (it provides some custom event handlers when text is entered, but to all intents and purposes, it's a regular TextBox).

I wanted to style my TextEntryBox, this time including a button within my ControlTemplate (this will eventually toggle an on-screen keyboard pop-up, but that's another blog post!). I came up with this:


All's well and good, until I want to try and handle the Click event for that button within my TextEntryBox class. Even Matthew MacDonald's "Pro WPF in C# 2008" which has proved a lifesaver for all things WPF since I've been working with this technology only had the following words of wisdom;

"You can't attach event handlers in the control template. Instead, you'll need to give your elements recognizable names and attach event handlers to them programmatically in the control constructor"

But whatever I tried I couldn't access the event in my constructor, until I remembered the seperation between the visual and logical trees in WPF.

The template is applied at runtime, and so elements contained within it it are part of the visual tree. My class, and therefore my class' constructor is executed within the logical tree, so I needed to attach my event handler after the template had been applied. You can do this by overriding OnApplyTemplate in your class, obtain the template that's being applied, and then you have access to the named button's events, like this:

public override void OnApplyTemplate()
{
    DependencyObject d = GetTemplateChild("PART_KeyboardPopupButton");
    if (d != null)
    {
        (d as Button).Click += new RoutedEventHandler(KeyboardPopupButton_Click);
    }

    base.OnApplyTemplate();
}

Note the null check, as someone could have applied a completely different template to the object.


Share this: