Al Kepp
Al Kepp

Reputation: 5980

How to add an event handler to object in ControlTemplate

How to programmatically add an event handler to an object which exists only in ControlTemplate of another object?

I work with Silverlight 4. I want to use control ColorSelector from a third party DLL (Liquid). It looks like combobox, but is implemented differently. (It was probably made for and older version of Silverlight when there was no system ComboBox.) The class ColorSelector derives from ContentControl, and its look is implemented using ControlTemplate defined in a xaml file.

In the fact it is a control which looks like combo box, but programatically its object doesn't derive from combo box. And now I am stuck, because I'd like to programatically access the combo box object I can see on screen. Normally if it was a real standard ComboBox, I would use events DropDownOpened and DropDownClosed to know when the box is shown and hidden respectively. But this color selector doesn't provide these events. But it uses a ControlTemplete which defines the look of the ColorSelector as a DropDown object. That DropDown class is another class from the same dll, and its look is also defined by its ControlTemplate and that is the place where that mysterious combobox-like look is based. And I am now totally confused by all this.

How can I programatically access these visual controls which I can see on screen but aren't directly present in the code? Here is one simple example:

class ColorSelector : LiquidControl
class LiquidControl : ContentControl

<Style TargetType="local:ColorSelector">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:ColorSelector">
                <local:DropDown x:Name="RootElement">
                .....
                </local:DropDown>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

class DropDown : LiquidControl

<Style TargetType="local:DropDown">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:DropDown">
                <Grid x:Name="RootElement">
                    <Button x:Name="ElementButton">
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Now I create a new ColorControl in my code (new ColorControl()) and then I'd like to access that button defined in template of DropDown. How to do it?

Upvotes: 0

Views: 711

Answers (2)

Al Kepp
Al Kepp

Reputation: 5980

I have found a solution to my problem with change of the original DLL. It is based on the answer given by anivas. I put this code to DropDown.OnApplyTemplate:

        ElementPopup.Opened += (s, ea) => { DropDownOpened(this, ea); };
        ElementPopup.Closed += (s, ea) => { DropDownClosed(this, ea); };

These two events signal when the combobox is opened and closed respectively. (Combobox is implemented using those templates I didn't understand before, there is Popup object to display an opened combobox.)

Then, analogically, I added similar code to ColorSelector.OnApplyTemplate:

        _dropDown.DropDownOpened += (s, ea) => { DropDownOpened(this, ea); };
        _dropDown.DropDownClosed += (s, ea) => { DropDownClosed(this, ea); };

Now I have got these two new events in ColorSelector, which signal when its being opened or closed. And that is what I wanted.

Thanks to anivas! His answer didn't work itself but it showed me where to start. (If I derived the ColorSelector class, I lost its template and routed events. And also it uses DropDown which must be changed somehow too.)

Upvotes: 0

anivas
anivas

Reputation: 6557

I believe you don't have the source code for the control. Try this: Extend the ColorSelector override OnApplyTemplate call GetTemplateChild to get the button.

public override void OnApplyTemplate()
{
   var button = this.GetTemplateChild("ElementButton") as Button;
   .... Do whatever with button
   base.OnApplyTemplate();
}

Upvotes: 1

Related Questions