Why WPF style tag overrides the background color and other properties of my button?

Let's say I have a simple button in a WPF application in a grid with gray background:

enter image description here

<Button HorizontalAlignment="Center" VerticalAlignment="Center" Content="Hello" Width="100" Height="50" Background="#333333" BorderThickness="0"/> 

I want to change the MouseOver behaviour of my button by adding this code:

<Button.Style>
    <Style TargetType="{x:Type Button}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Border>
                        <Border.Style>
                            <Style TargetType="{x:Type Border}">
                                <Style.Triggers>
                                    <Trigger Property="IsMouseOver" Value="True">
                                        <Setter Property="Background" Value="#404040"/>
                                    </Trigger>
                                </Style.Triggers>
                            </Style>
                        </Border.Style>
                        <Grid Background="Transparent">
                            <ContentPresenter></ContentPresenter>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Button.Style>

The problem is: why the color changed and the text moved by adding this style tag?

enter image description here

Upvotes: 2

Views: 672

Answers (1)

thatguy
thatguy

Reputation: 22079

A ControlTemplate in WPF defines the appearance and the visual states, like mouse-over or focused, of a control. If you override a control template, you start from scratch. You cannot override specific parts only, like the mouse-over state and leave out the rest. The control will not work properly. You have to recreate the whole control template or take a default one and adapt it.

Every control has a default template, that is usually extracted and modified according to the given requirements. You can find all parts, states and some examples of control templates on MSDN, e.g. for Button. If you do not implement any of the defined states or parts, your button might not behave as expected, as you already noticed.

The control template samples on MSDN might be incomplete or outdated. You can extract the default control templates using Blend or Visual Studio. For instructions on that, see this related post.

The problem is: why the color changed and the text moved by adding this style tag?

The Background of any control in your template gets its default value, the value that you assigned explicitly or the value provided by a markup extension or binding. In your example all background values are either missing, hence default, or hardcoded.

If you want to use the background color defined on the templated Button, you have to use a TemplateBinding or a RelativeSource binding on TemplatedParent, e.g. on your Border:

<Border Background="{TemplateBinding Background">

This will apply the value of Background that was assigned to a templated button (directly or through a Style) to your Border. In essence template bindings enable styling of your control.

Why was the text moved? That is simply because you did not define it otherwise. Remember, you start from scratch. Try setting the ContentPresenter like this and you will see that the Content is centered:

<ContentPresenter HorizontalAlignment="Center"
                  VerticalAlignment="Center"/>

Another remark on your mouse-over style. In a control template you define the states either using the VisualStateManager or by defining triggers on your control template.

For the mouse-over state for example, you would first assign a name to your Border:

<Border x:Name="ButtonBorder" ... >

Then you could add a trigger to the control template referencing this name to set the Background:

<ControlTemplate.Triggers>
   <Trigger Property="IsMouseOver" Value="True">
      <Setter TargetName="ButtonBorder" Property="Background" Value="#404040"/>
   </Trigger>
</ControlTemplate.Triggers>

Control templates are not quite trivial and easy to get right. I recommend you to read this introduction to creating control templates to get a better understanding how they work.

Upvotes: 6

Related Questions