This article is compatible with the latest version of Silverlight.
Introduction
The ContentControl is often overlooked when building Silverlight apps. It’s used inside many controls such as the Button or ChildWindow, but it also turns out to be quite useful on it’s own for separating content from presentation.
Here is a sample of the technique I will be describing. The buttons swap between two completely different “themes” for the same UserControl but the XAML for the UserControl doesn’t contain any theme elements at all, just layout and content. It’s not Picasso, but it will do to illustrate the concept:
You can grab the source files here.
This is what the layout looks like:
I should point out that the concept I am describing is not how to switch from one theme to another (I’m using quick and dirty code to do that). Rather, it is about organizing your XAML files to keep them free from borders and rectangles etc that are purely presentation.
In the layout screenshot above, you can see there are no theme-specific elements in the object tree. The child UserControls (“LeftButtons” etc) also just contain content such as the Buttons and the ScrollViewer. So where are the theme elements? They are in the styles for the ContentControls; in this case in App.xaml, but they could easily be placed in a resource dictionary. The XAML for the page is now clean and easy to maintain since it doesn’t have the clutter of all the decorative elements. I can quickly see it and understand it and I can work with the whole Object Tree expanded in Blend.
Layout and Content vs. Presentation
It has always been good practice in web applications to use styles to keep presentation separate from the layout and content of the information. CSS files provide that function for HTML pages, but CSS tends to use lots of images for backgrounds and buttons, whereas Silverlight lets us define most/all of our presentation in XAML. This article describes a way to do, in part, for XAML what CSS did for HTML. It’s not always easy or practical to try and remove the presentation from content, but the kind of situations where this works best are:
- Title bars
- Main application background
- Tool bars
- Reusable views such as log-in screens
- Sidebars
- Footers
They are patterns where there is content inside a decorative border, and prime targets for using a ContentControl style template to remove the decorative elements of the presentation from the content.
Step 0
This is not some geeky reference to 0-based indexes, rather it’s something you should do before you start throwing controls and resource dictionaries at a project. Stop and take a moment to design your overall application layout. This will usually end up with a group of areas of the screen defined for content such as “Title”, “Menu/Navigation”, “Side Navigation”, “Footer” etc. These may be suitable candidates for ContentControls.
Step 1
The ContentControl is not immediately visible from the Controls toolbar. The easiest way to find it is to open up the Assets fly-out at the bottom of the Controls toolbar and use the search box in the fly-out to type “ContentControl”. Once you select it you can either draw it on the design surface, or double click the button that is now on the Controls toolbar to place it as a child control of the currently selected element.
Step 2
Right click the ContentControl and select “Edit Template”, and “Edit a Copy…”. You will be prompted to create a new “Style Resource”, as shown in the image to the left.
You have three options for where to store the style resource:
- Application – will be stored in the App.xaml file.
- This document – will be stored in a Resources section within the current UserControl
- Resource Dictionary – will be stored in a resource dictionary in a separate file, either in the current project, or another assembly that is part of the solution.
|
Ultimately, you want the style in it’s own resource dictionary, but quite often it is easier, from a design point of view, to create the style resource in the same document as the ContentControl, and then move it to a resource dictionary when you have finished editing the template. This is because saving the style resource in another file takes it “out of context” when editing, so you are making your changes without seeing it in the page with the actual content it will contain.
Step 3
Place your ContentPresenter control. The default control template for a ContentControl is a single ContentPresenter. You can place whatever controls you like in this template, as long as you have at least one ContentPresenter. If you are placing the ContentPresenter beneath other elements, be sure to uncheck “IsHitTestVisible” on any that will cover parts of the content that the user will need to interact with. If the template is for a title or footer, this may not be necessary.
The Benefits
I’ve briefly mentioned a couple of reasons that this can be a helpful practice, but it’s worth looking at the benefits in more detail.
Cleaner XAML
Sometimes you need to work with the XAML, rather than Blend, to use language features that Blend just doesn’t support such as custom attached properties. Keeping the UserControls free from all the presentation elements makes for a XAML file that is quick to browse and change.
Reusable Resources
If you organize your resource dictionaries carefully you will end up with visual designs that can be reused again and again. This is especially true if you are creating a suite of applications for your business or client. The resource dictionaries can be kept in their own assemblies and managed separately by your designer or UI developer/team.
Different Themes, Same Application
A recent project I worked on required a single Silverlight application to show very different themes for different customers. Not just a difference of color or size, but large differences such as different logos, animations, and graphics. All customer-specific theme content had to live in its own resource dictionary. I could detect which theme should be applied at application start-up and choose the appropriate resource dictionary to load into the Application resources, but still needed a way to keep each user control free of customer-specific content.
We use the Prism MVVM framework, so I could just create different views for each customer, but that would be a big hassle to maintain, and feels wrong since each view does exactly the same thing.
I solved this problem by wrapping the main layout areas inside ContentControls and customizing the style control templates for them. In the sample at the top of the page I have just put all the styles into App.xaml and have named the styles for each theme differently, but in the real-life project, I used a different technique described here to load in the right resources dictionary when the application started up. In that approach the resource dictionaries all have the same style keys since only one dictionary will be used.
Summary
In this post I have described how to separate layout and content from theme elements using ContentControls, and I listed the kinds of areas that lend themselves to this approach:
- Title bars
- Main application background
- Tool bars
- Reusable views such as log-in screens
- Sidebars
- Footers
Finally I described how to apply the technique, and discussed the benefits which are: having cleaner XAML, generating reusable resources, and using different themes within the same application.