In my last post, I introduced the current set of layout panels provided by Silverlight.FX. All of those panels positioned their children by computing the size and position based on desired and available sizes, i.e. by overriding the measurement and arrangement API, as expected of Panel-based elements.
This post is about a control named TemplatePanel. TemplatePanel is similar to other panels, in that it has some children that it is responsible for positioning. However it doesn't take on measurement and arrangement itself. It uses a different strategy - specifically it is associated with a template that defines a scaffolding that contains one or more named ContentPresenter elements, and TemplatePanel matches its children to the individual ContentPresenter elements within that scaffolding for positioning and laying them out.
There are a couple of analogies to other well established precedents that best explain the model:
- Master pages in ASP.NET. If you're an ASP.NET developer you're probably familiar with these. Master pages can contain ContentPlaceHolder controls, and at runtime contents of a content page are inserted into the control tree defined in the master page at the right spots. TemplatePanel is similar, but is more general-purpose. It isn't tied to pages and navigation, and can instead be placed anywhere in the visual tree. At the same time it can be used to define the structure of pages for the classic navigation scenario as well.
- Slide master in Powerpoint. This is one that all of you are likely to know what I am talking about. Slide masters define regions that specify where the title of the slides go, where the content goes, amongst other non-editable element such as a logo image. Each slide then defines the content for that slide instance, and the end result is a visual merge of the content in the master with the content on the slide.
The Silverlight Store application makes extensive use of this feature. When you run the app, you'll see different sections of the page have a similar look: a header, a body and a footer. They are implemented by using three instances of the TemplatePanel control. The TemplatePanel control allows defining the scaffolding around the elements that is common to each section just once, and optionally in a theme, so you can swap in and out the scaffolding without touching every page.
Here is how a TemplatePanel is typically declared:
<fxui:TemplatePanel Style="{StaticResource sectionStyle}">
</fxui:TemplatePanel>
And then in a resources section, the sectionStyle is defined as follows:
<Style x:Key="sectionStyle" TargetType="fxui:TemplatePanel">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="fxui:TemplatePanel">
<fxui:XBorder CornerRadius="4"
BorderThickness="1" BorderBrush="#20000000"
ShadowSpread="4">
<fxui:XBorder.ShadowBrush>
<LinearGradientBrush>...</LinearGradientBrush>
</fxui:XBorder.ShadowBrush>
<fxui:XGrid Rows="31,*,40" Background="White">
<Border Grid.Row="0"
BorderThickness="0,0,0,0.5" BorderBrush="#80000000">
<Border.Background>
<LinearGradientBrush>...</LinearGradientBrush>
</Border.Background>
<ContentPresenter x:Name="header" Margin="4" />
</Border>
<Grid Grid.Row="1" Background="{TemplateBinding Background}">
<ContentPresenter x:Name="body" Margin="4" />
</Grid>
<Border Grid.Row="2"
BorderThickness="0,0.5,0,0" BorderBrush="#80000000">
<Border.Background>
<LinearGradientBrush>...</LinearGradientBrush>
</Border.Background>
<fxui:XGrid Columns="*,Auto">
<ContentPresenter x:Name="footerLeft"
HorizontalAlignment="Left" VerticalAlignment="Stretch"
Margin="4,4,2,4" />
<ContentPresenter x:Name="footerRight" Grid.Column="1"
HorizontalAlignment="Right" VerticalAlignment="Stretch"
Margin="2,4,4,4" />
</fxui:XGrid>
</Border>
</fxui:XGrid>
</fxui:XBorder>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

The screenshot shows what the ControlTemplate looks like visually with the regions defined by the ContentPresenters as shown in red. These regions are filled with actual content defined within individual TemplatePanel instances.
There are a couple of nice implications of the TemplatePanel's visual structure being defined in resources:
- The style is reusable. Multiple TemplatePanel instances can refer to the same style, and you can have a consistent look across your application without having to duplicate the XAML each time.
- Resources form the basis of theming. You can define different versions of the Style in each theme, and as long as the names assigned to the ContentPresenters are consistent, everything gets matched up at runtime just fine.
Finally here is a TemplatePanel example with some actual content (for the shopping cart section in the Store app). You can see the TemplatePanel.ContentName attached property on the individual elements to match them up to the ContentPresenters defined in the control template.
<fxui:TemplatePanel Style="{StaticResource sectionStyle}">
<TextBlock fxui:TemplatePanel.ContentName="header"
Text="Shopping Cart" />
<data:DataGrid fxui:TemplatePanel.ContentName="body">
...
</data:DataGrid>
<Button fxui:TemplatePanel.ContentName="footerRight"
Content="Checkout" />
</fxui:TemplatePanel>
As you can see the contents of a TemplatePanel are really clean with minimal layout information, and the complex layout scaffolding including borders, shadows, brushes, Grids etc. are all hidden away from the main user interface definition. In fact, what you have is separation of content and layout.
I've also used TemplatePanel in the Store app to define the About dialog structure. TemplatePanel works in a variety of scenarios that require some common chrome defined around and between content that you want to share.
There are more advanced uses of TemplatePanel by using TemplateBinding to bind bits of the visual structure to instance-specific properties (as shown in the snippet above). For example, if I want to bind the Background of the body in the template to Background of the instance, I can use a TemplateBinding. Again look at the About dialog from the sample as an example.
Hope you found this interesting ... one of the focus areas and goals of Silverlight.FX is to enable the declarative portion of your app be more concise, and TemplatePanel is one of the features in that direction. As always, I'd love to hear your thoughts and ideas. Would this be a useful building block for your own applications?
Posted on Tuesday, 3/10/2009 @ 8:14 AM
| #
Silverlight