Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
TemplateBinding: a bridge between styles and templates

This is partially a follow-up to my last post contrasting control templates and styles. Like I mentioned before I've been working on an application that has required a custom theme. In addition to styling the standard controls like text boxes and expanders, we've had to create a number of custom controls as well. That has added up to a lot of control templates.

This recent work has emphasized the importance of the template binding. (Beatriz Costa first helped me get a handle on template binding here.)  TemplateBinding is a special markup extension specifically designed for binding values in a template. (That's a bit of a circular definition, isn't it?) TemplateBinding is the mechanism that allows us to inject values into our templates, or to parameterize them.

An Example

First, imagine that we have a resource dictionary where we have defined a set of brushes that we'll use as the palette for our application. We might go about building a control template for the ToolTip control like this:

<ControlTemplate x:Key="ToolTipTemplate"
                 TargetType="ToolTip">
    <Grid>
        <Border x:Name="DropShadow"
                Focusable="False"
                CornerRadius="3"
                Background="Black"
                Opacity="0.4"
                Margin="3 3 0 0" />
        <Border Background="{DynamicResource NormalControlBackground}"
                BorderBrush="{DynamicResource NormalControlBorder}"
                BorderThickness="1"
                Margin="0 0 3 3"
                CornerRadius="3"
                Padding="6">
            <ContentPresenter TextBlock.Foreground="{DynamicResource NormalControlText}" />
        </Border>
    </Grid>
</ControlTemplate>

This control template is too rigid. What if another team member needs to create a special ToolTip in just one place with a background color other than NormalControlBackground?  They would probably write some markup like this:

<Button Content="History Eraser Button">
    <Button.ToolTip>
        <ToolTip Background="Red" 
                 Foreground="White"
                 Content="Don't press it!" />
    </Button.ToolTip>
</Button>

Sadly, they would discover that it wouldn't work. The control template doesn't know anything about the properties we set on the ToolTip in the markup. Everything is defined in the control template and it's self contained.  We really want the template to be able to use the properties that are set on the control. The template above can be rewritten to do that:

<ControlTemplate x:Key="ToolTipTemplate"
                 TargetType="ToolTip">
    <Grid>
        <Border x:Name="DropShadow"
                Focusable="False"
                CornerRadius="3"
                Background="Black"
                Opacity="0.4"
                Margin="3 3 0 0" />
        <Border Background="{TemplateBinding Background}"
                BorderBrush="{TemplateBinding BorderBrush}"
                BorderThickness="{TemplateBinding BorderThickness}"
                Margin="0 0 3 3"
                CornerRadius="3"
                Padding="{TemplateBinding Padding}">
            <ContentPresenter TextBlock.Foreground="{TemplateBinding Foreground}" />
        </Border>
    </Grid>
</ControlTemplate>

Using the template bindings allows the control template to pick up the values that are supplied directly on the element, or on the style applied to the element. That means that the Button markup above would work, or we could even create a style for the special case tool tip that looks like this:

<Style x:Key="WarningStyle" TargetType="ToolTip">
    <Setter Property="Background" Value="Red" />
    <Setter Property="Foreground" Value="White" />
</Style>

Handling the Default Values

If you use a control template with template binding, and don't provide any values on the control, what happens? The default values of the bound properties are used. There are many cases where this is not what you want though. If your intent was to have a global look for tool tips based on our first example, then you want the template to use some specific brushes as well a few other things.

In this case, you can use a style to set the desired defaults. To apply a style to a control for an entire application, set its TargetType and don't provide a key. The style will also need to be added to (or merged into) the resource dictionary of application. The style is also used to set the custom template for the control (otherwise you'd have to set the Template property on every instance of the control.)

Here's an example style to accompany our template:

<Style TargetType="ToolTip">
    <Setter Property="Background" Value="{DynamicResource NormalControlBackground}" />
    <Setter Property="BorderBrush" Value="{DynamicResource NormalControlBorder}" />
    <Setter Property="BorderThickness" Value="1" />
    <Setter Property="Foreground" Value="{DynamicResource NormalControlText}" />
    <Setter Property="Padding" Value="6" />
    <Setter Property="Template" Value="{DynamicResource ToolTipTemplate}" />
</Style>

I'm interested in feedback. If you find this useful, or too basic, or whatever, please let me know!


Posted 07-04-2008 12:30 AM by Christopher Bennage

[Advertisement]

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)