views:

28

answers:

2

Hi, I'm using a ControlTemplate for defining the appearance of my buttons in a WPF application. Additionally I would like to use styles to set certain aspects of my buttons. These styles should set properties on elements defined in the ControlTemplate, like (simplified):

<Window.Resources>
    <ControlTemplate x:Key="Template1" TargetType="Button">
        <Grid>
            <Rectangle Name="rect" Fill="White" Stroke="Blue" StrokeThickness="2"/>
            <TextBlock Name="text" Text="Hallo" Foreground="Red" VerticalAlignment="Center" HorizontalAlignment="Center"/>
        </Grid>
    </ControlTemplate>
    <Style x:Key="Style1" TargetType="Button" >
        <Setter TargetName="rect" Property="Fill" Value="Red"/>
    </Style>
</Window.Resources>

Now the compiler complains that the TargetName "rect" isn't a valid target which I can understand since an untemplatized Button doesn't contain an element named "rect".

I know that I could change the style to setting the complete template, but I would like to avoid that (because the template is much more complex than shown here and I do not want to duplicate it for each style...)

Is it possible to achieve this behaviour? Perhaps by setting the TargetType right? Any other ideas?

+1  A: 

You can NOT override only part of the control template. You can either change everything or nothing.

You can have setters for properties on the style though.

NVM
+1  A: 

The standard pattern is to use TemplateBinding in the control template to bind to properties of the control itself, and then set the properties on the control in the style. For example:

<Window.Resources>
    <ControlTemplate x:Key="Template1" TargetType="Button">
        <Grid>
            <Rectangle Name="rect" Fill="{TemplateBinding Background}" Stroke="Blue" StrokeThickness="2"/>
            <TextBlock Name="text" Text="Hallo" Foreground="Red" VerticalAlignment="Center" HorizontalAlignment="Center"/>
        </Grid>
    </ControlTemplate>
    <Style x:Key="Style1" TargetType="Button" >
        <Setter Property="Background" Value="Red"/>
    </Style>
</Window.Resources>

This will bind the Fill property on rect to the Background property on the Button. The style will set the Background property to Red, which will cause the Fill to be set to Red.

In order to set defaults, you would normally create a style that set the template as well as the other properties:

<Window.Resources>
    <Style x:Key="BaseStyle" TargetType="Button">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Grid>
                        <Rectangle Name="rect" Fill="{TemplateBinding Background}" Stroke="Blue" StrokeThickness="2"/>
                        <TextBlock Name="text" Text="Hallo" Foreground="Red" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Background" Value="White"/>
    </Style>
    <Style x:Key="Style1" TargetType="Button" BasedOn="{StaticResource BaseStyle}">
        <Setter Property="Background" Value="Red"/>
    </Style>
</Window.Resources>

The first style will apply the template and set Background to White, so the rectangle will be white. The second style inherits from the first one but sets the Background to Red, so the rectangle will be red.

Quartermeister