Reputation: 111
I will start with the code. Here is the simple button:
<Grid>
<Button Height="20" Width="100"
Background="Brown"
BorderBrush="Blue"
Foreground="Aqua">Test button</Button>
</Grid>
I set Background, BorderBrush and Foreground in Button control.
Below I have a code, exactly the same result, but with defining style and template:
<Window.Resources>
<Style TargetType="Button">
<Setter Property="Content" Value="foo"></Setter>
<Setter Property="BorderBrush" Value="Blue"></Setter>
<Setter Property="Background" Value="Brown"></Setter>
<Setter Property="Foreground" Value="Aqua"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}">
<ContentPresenter Content="{TemplateBinding Content}"></ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Button Height="20" Width="100">
Test button
</Button>
</Grid>
Here is what confuses me:
I declare style and template, then I declare ControlTemplate
, then inside ControlTemplate
I declare Border
and then... Background
inside Border
tag. WHY? It's a background of button's content - it has nothing to do with border. That doesn't make sense for me.
What's even more weird, now every poperty, that I want to set for Button (like background for example) I have to set for Button's border. Even button's content. Why ContentPresenter
must be inside Border
?
Btw. if I ditch border and just want content then, this is correct:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ContentPresenter Content="{TemplateBinding Content}"></ContentPresenter>
</ControlTemplate>
</Setter.Value>
</Setter>
So, my question would be: Why when declaring template I have to set Background
of the button inside button's Border
?
This example with Button
it's just an example. More general answer/explanation would be great!
Upvotes: 2
Views: 604
Reputation: 8843
When you override the template of a Control
like Button
you essentially control the whole look and feel of that Control
. You are replacing the visual tree of that Control
.
So when you put a Button
in your application, it will contain the subtree that is found in its ControlTemplate
.
This can be observed in Visual Studio 2015's Live Visual Tree pane or in Snoop:
Button
is a ContentControl
, that means that its ContentPropertyAttribute
is set to "Content"
. A ContentPresenter
in a ContentControl
's ControlTemplate
will pick up whatever you've put inside the ContentControl
's Content
property (you don't even need the TemplateBinding
for ContentPresenter
's Content
in your case). If you use a simple string Content
like <Button Content="Whatever" />
it will be converted to <TextBlock Text="Whatever" />
, hence the TextBlock in the visual tree in the picture.
In the example you provided the Border
element is used to let the user be able to set a Background to the Button
. Because ContentPresenter
doesn't have a Background
property you have to wrap it in a Border
element and set the Background
on the Border
.
I think the name Border
might be confusing, it's not always strictly used for rendering borders (although in this case, it is used for that and for the Background
as well).
I hope this kinda makes sense, if you have further questions, feel free to ask.
Upvotes: 2