Custom control's properties not changing when used in a template

352 Views Asked by At

I have created a custom control (inherits Control) that exposes a single enumerated DependencyProperty. The default control template renders differently based on the selected value for the property using Triggers to turn elements on/off. The control works great when placed directly into a UserControl for viewing in the UI. However, the point of the control is to exist as part of a large composite control so it is also used in the ControlTemplate of another custom control. When I do so, changes to the dependency property are not recognized by the control. I verified this by adding a PropertyChangedCallback to the dependency property and setting a break point which is never hit.

For example, when I use "CustomControl" in a template like this:

<ControlTemplate>
    <my:CustomControl EnumProperty="EnumValue" />
</ControlTemplate>

The EnumProperty (which is a DependencyProperty) is not changed to "EnumValue" and it remains the default value. And, as I said, a breakpoint in the PropertyChangedCallback for the DP is never called.

What am I missing?

UPDATE

Here is a cleansed version of my control:

public class CustomControl : Control
{
    static CustomControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl), new FrameworkPropertyMetadata(typeof(CustomControl)));
    }

    public StandardIcon()
        : base()
    {
        BorderType = BorderType.None;
    }

    public static readonly DependencyProperty BorderTypeProperty = DependencyProperty.Register("BorderType", typeof(BorderType), typeof(CustomControl), new PropertyMetadata(BorderType.None));

    public BorderType BorderType
    {
        get { return (BorderType)GetValue(BorderTypeProperty); }
        set { SetValue(BorderTypeProperty, value); }
    }
}


<Style TargetType="{x:Type local:CustomControl">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:CustomControl}">
                <Border x:Name="Rectangle"
                        BorderBrush="{TemplateBinding Foreground}"
                        BorderThickness="0"
                        HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch">
                    <ContentPresenter ContentSource="Content" />
                </Border>

                <ControlTemplate.Triggers>
                    <Trigger Property="BorderType" Value="Rectangle">
                        <Setter Property="BorderThickness" TargetName="Rectangle" Value="2" />
                    </Trigger>
                    <Trigger Property="BorderType" Value="RoundedRectangle">
                        <Setter Property="BorderThickness" TargetName="Rectangle" Value="2" />
                        <Setter Property="CornerRadius" TargetName="Rectangle" Value="5" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

And this is how it is being used within another control (notice that it is in a DataTemplate and not a ControlTemplate as I originally indicated).

<Style TargetType="{x:Type local:OtherControl}">
    <Setter Property="FontFamily" Value="{x:Static theme:StandardFonts.FontFamily}" />
    <Setter Property="FontSize" Value="{x:Static theme:StandardFonts.FontSizeXS}" />
    <Setter Property="FontWeight" Value="Bold" />
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
                <local:CustomControl BorderType="{Binding TemplatedParent.BorderType, RelativeSource={RelativeSource TemplatedParent}}"
                                     Foreground="{Binding TemplatedParent.Foreground, RelativeSource={RelativeSource TemplatedParent}}" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

And then it is used like this:

<controls:OtherControl Foreground="Red" BorderType="Rectangle" />

The Foreground property IS changing as expected. When I change the Foreground of the OtherControl, the Foreground of the CustomControl is changed. But the BorderType property is not being respected - it always renders with the default BorderType.None value.

1

There are 1 best solutions below

3
On

The parent of your ControlTemplate needs to have something for your CustomControl to bind to. Then, you bind the CustomControl in your template to the parent.

In the following example, I'm using a Border to template a Button, which binds its BorderBrush to the Button's Background:

<ControlTemplate TargetType="{x:Type Button}">
    <Border BorderBrush="{TemplateBinding Background}" />
</ControlTemplate>

Replace Button with your "large composite control" and Border with my:CustomControl and you should be set...