chris
chris

Reputation: 111

Understanding Style and Template in XAML/WPF

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:

  1. 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.

  2. 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

Answers (1)

Szabolcs D&#233;zsi
Szabolcs D&#233;zsi

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:

Visual Tree of default Button

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

Related Questions