Reputation: 684
Let's say I have a simple button in a WPF application in a grid with gray background:
<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?
Upvotes: 2
Views: 672
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