Themes and dynamic loading in Silverlight

Asim NazirProject Manager
Published:
A theme is a collection of property settings that allow you to define the look of pages and controls, and then apply the look consistently across pages in an application. Themes can be made up of a set of elements: skins, style sheets, images, and other resources.

Recently I was working on a task where I was to apply themes to a Silverlight application. After doing some RnD, I created two different themes for most commonly used controls e.g. Button, TexBlock, TextBox and I was hoping that it will work straight away without any issues but I was stuck on a few points which were: loading and setting resources at run time. After spending some time on it I was able to get it running. This is where I decided to write a short article with running example of themes and dynamic loading of themes in Silverlight 4.

In this article, We will cover styling using standard as well as BasedOn approach. Let us start with standard approach where we will be creating two different themes for a TextBlock control.

Style A
    <Style x:Key="tbNormal" TargetType="TextBlock">
                              <Setter Property="Margin" Value="0,0,10,0"/>
                              <Setter Property="Foreground" Value="#FF000000"/>
                              <Setter Property="FontFamily" Value="Arial"/>
                              <Setter Property="FontSize" Value="11"/>
                              <Setter Property="VerticalAlignment" Value="Center"/>
                              <Setter Property="HorizontalAlignment" Value="Left"/>
                          </Style>

Open in new window


Style B
    <Style x:Key="tbNormal" TargetType="TextBlock">
                              <Setter Property="Margin" Value="0,0,10,0"/>
                              <Setter Property="Foreground" Value="AliceBlue"></Setter>
                              <Setter Property="FontFamily" Value="Arial"/>
                              <Setter Property="FontSize" Value="11"/>
                              <Setter Property="VerticalAlignment" Value="Center"/>
                              <Setter Property="HorizontalAlignment" Value="Left"/>
                          </Style>

Open in new window


The only difference between the two themes is the use of different Foreground property. Now, we can further improve the theme XAML by using BasedOn property like this:

Style A
    <Style x:Key="BasicStyle" TargetType="TextBlock">
                              <Setter Property="Margin" Value="0,0,10,0"/>
                              <Setter Property="Foreground" Value="#FF000000"/>
                              <Setter Property="FontFamily" Value="Arial"/>
                              <Setter Property="FontSize" Value="11"/>
                              <Setter Property="VerticalAlignment" Value="Center"/>
                              <Setter Property="HorizontalAlignment" Value="Left"/>
                          </Style>

Open in new window


Style A: Normal
<Style x:Key="tbNormalBO" BasedOn="{StaticResource BasicStyle}" TargetType="TextBlock"/>

Open in new window


Style A: Bold
    <Style x:Key="tbBoldBO" BasedOn="{StaticResource BasicStyle}" TargetType="TextBlock">        
                              <Setter Property="FontWeight" Value="Bold" />
                          </Style>

Open in new window


Here, point to remember is, if we don’t add the key attribute to a style and further don’t apply staticResource to a corresponding control, this style will be applied to all the elements on a particular form. Below XAML shows it all:

1.      TexBlock with tbNormal theme:
<TextBlock Height="23" HorizontalAlignment="Left" Style="{StaticResource tbNormal}" Name="textBlock1" Text="KeyBased Normal style" />

Open in new window


2.      TexBlock with tbBold theme:
<TextBlock Height="23" HorizontalAlignment="Left" Style="{StaticResource tbBoldBO}" Name="textBlock3" Text="KeyBased Based-On style"/>

Open in new window


3.      TexBlock with no theme style specified – in this case BasicStyle will be applied depending upon the TargetType attribute.
<TextBlock Height="23" HorizontalAlignment="Left" Name="textBlock2" Text="Apply style to all textBlocks with no key define approach." />

Open in new window


Once styles are built, simply place these style in a separate XAML file, say TextBlock.XAML. This will do the job for TextBlock control. We can follow the same approach for creating themes for any other controls. One thing we need to make sure is, for all the style files, the Build Action needs to be set to Resource – as shown in the figure below:
 
Setting the Build ActionFigure 1 Setting the Build Action

Like standard Skin file – as in case of ASP.Net themes, we will refer all the resource to a corresponding ResourceSkin file like:

<ResourceDictionary
                      	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                      	xmlns:basics="clr-namespace:System.Windows.Controls;assembly=System.Windows"	
                      	xmlns:primitives="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows"
                      	xmlns:System="clr-namespace:System;assembly=mscorlib"
                      	xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"
                      	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
                          
                        <ResourceDictionary.MergedDictionaries>        
                              <ResourceDictionary Source="TextBlock.xaml"/>
                        </ResourceDictionary.MergedDictionaries>
                      </ResourceDictionary>

Open in new window

Finally, we need to load appropriate resources depending upon the selected theme. This can be done under Application StartUp event using below code:

if (this.CurrentSkin != null && this.CurrentSkin.ToLower().Equals("styleone"))
                      {
                      Uri uri = new Uri("/SLTheming;component/Themes/StyleOne/StyleOneSkin.xaml", UriKind.Relative);
                      ResourceDictionary dictionary = new ResourceDictionary();
                             dictionary.Source = uri;
                             Application.Current.Resources.MergedDictionaries.Add(dictionary);
                      }
                      else 
                      {
                      Uri uri = new Uri("/SLTheming;component/Themes/Default/DefaultSkin.xaml", UriKind.Relative);
                             ResourceDictionary dictionary = new ResourceDictionary();
                             dictionary.Source = uri;
                             Application.Current.Resources.MergedDictionaries.Add(dictionary);
                      }

Open in new window


The only drawback with this approach is, resources are not available at design time. We can overcome this by keeping default theme at design time and changing theme at runtime if really need to apply any other theme.

Download and run the attached code to see things running. Happy theming!
0
3,586 Views

Comments (0)

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.