Recommended

Skip Navigation LinksHome / Articles / View Article

Skinning and Styling Silverlight Controls

+ Add to SilverlightShow Favorites
1 comments   /   posted by Radenko Zec on Nov 10, 2009
(4 votes)
Categories: Learn , Tutorials , QuickStarts

1. Introduction

To change a look of Silverlight controls the way that you want it to, you can style it by modifying default template of the control. Silverlight controls have XAML based templates that can easily be changed and saved as new template. You can change the look for entire control without writing any line of code in C#. It can be done completely in XAML. However if you want to do minor modifications to the look of control such as change background color or default font you can do it directly in XAML without need to change default template of the control.

For example we can simple change foreground color of text for TabItem control by setting foreground property directly in XAML of that control without need for changing template for that control :

 

<my:TabItem Header="Buy or earn chips" Foreground="#FF6A1D38">
<Grid>
</Grid>
</my:TabItem>

In this article I will show you how to build custom template for Silverlight 3 TabControl for imaginary poker game site. There are many poker sites out there and why not making one in Silverlight? Most poker sites have some kind of TabControl on main page. Often there is a tab button for buying chips.This button is usually colored with different color from other buttons to be easier to notice.

 

2. Demo and source code

You can download the source code to go with this article here.You will need Visual Studio 2010 beta 2 to open this solution.

This is how default template for Silverlight TabControl looks like without any modifications:

BeforeStylingTab

Demo of control after my modifications :

 

3. Performance considerations

Each element in template is instantiated per instance for control that use that particular template. For best performance it is important to have smaller number of elements in template. Build-in types in templates are also almost always faster than custom types that you can create for that template. For the best load times for control try to modify common template elements instead of creating your own.

 

4. Modifying default template for TabControl and TabItem

Easiest way to modify default template for control is to that in Expression Blend. In this section I will show you how I have modified template for TabControl and TabItem.

In Expression Blend menus called Objects and Timeline locate your control for witch you want to modify template, right click on it and choose Edit Template –> Edit a Copy . After that Expression Blend will ask you where to save copy of template in UserControl.Resources or in Application.Resources. For this example I will save all templates in Application.Resources in App.xaml file.

 

EditTemplate

After that I will get copy of template for TabControl. In this case we have few objects in the template: TemplateTop, TemplateBottom, TemplateLeft, TemplateRight. The objects in the template that are referenced by the code are called parts. We can view the parts in the Parts panel when you are editing a control template in Expression Blend.

TemplatePart

We will not change parts in this template. We will just change few simple properties for main template for TabControl such as Background.

<Style x:Name="TabControlStyleDemo" TargetType="controls:TabControl">
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFFFFFFF" Offset="0"/>
<GradientStop Color="#FF94BFB5" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="BorderBrush">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFA3AEB9" Offset="0" />
<GradientStop Color="#FF8399A9" Offset="0.375" />
<GradientStop Color="#FF718597" Offset="0.375" />
<GradientStop Color="#FF617584" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
</Style>

After that we need to change TabItem template. First we need to change background color of TabItem.

<Setter Property="Background" Value="#FF94BFB5"/> 

 

5. VisualStateManager

In the default template for TabControl there is a class called VisualStateManager that is responsible for taking care of the transitions between different visual states of control. VisualStateManager have attached property called VisualStateGroups that represents states of a control. Each of these group can have number of different states. For example TabControl template has VisualStateGroup called CommonStates that has three states Normal, MouseOver and Disabled and another VisualStateGroup called FocusStates that has two state  Focused and Unfocused. A state like MouseOver state in this example can have Storyboard that is defining how animation will look and how long will run during that state.

For this example I will just change gradient colors on MouseOver VisualState for Gradient Top.

 

<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimationUsingKeyFrames BeginTime="0" Duration="00:00:00.001" Storyboard.TargetName="BorderTop" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="0" Value="#FF448DCA"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="0" Duration="00:00:00.001" Storyboard.TargetName="GradientTop" Storyboard.TargetProperty="(Border.Background).(GradientBrush.GradientStops)[3].(GradientStop.Color)">
<SplineColorKeyFrame KeyTime="0" Value="#FF138B93"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="0" Duration="00:00:00.001" Storyboard.TargetName="GradientTop" Storyboard.TargetProperty="(Border.Background).(GradientBrush.GradientStops)[2].(GradientStop.Color)">
<SplineColorKeyFrame KeyTime="0" Value="#FF138B93"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="0" Duration="00:00:00.001" Storyboard.TargetName="GradientTop" Storyboard.TargetProperty="(Border.Background).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
<SplineColorKeyFrame KeyTime="0" Value="#FF138B93"/>
</ColorAnimationUsingKeyFrames>

 

6. Changing parts properties

As I sad before parts are named elements inside of a control template. Parts usually appear in template because control need to do something with them. 

I will need to change gradient colors and FontWeight for TemplateTopSelected and TemplateTopUnselected parts. If we need that our control display some custom font and not standard font type we can do it on very simple in Silverlight.

We need to do just few steps :

1. Right click on your Silverlight application project in the Solution Explorer and choose “Add->New Item”

2. Select your font and click OK button .

3. Select your font,and set the Build Action = “Resource” and the “Copy to Output Directory” = “Copy if newer”

4. After that we just need to set FontFamily to be our custom font. One important thing about this is that our custom font is not installed on client computer. It is only used by Silverlight plug-in for that particular site.

 

<Grid x:Name="TemplateTopSelected" Visibility="Collapsed" Canvas.ZIndex="1">
<Border Margin="-2,-2,-2,0" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1,1,1,0" CornerRadius="3,3,0,0">
<Border BorderBrush="#FFFFFFFF" BorderThickness="1" CornerRadius="1,1,0,0">
<Border.Background>
<LinearGradientBrush EndPoint=".7,1" StartPoint=".7,0">
<GradientStop Color="#FFFFFFFF" Offset="0"/>
<GradientStop Color="#FF138B93" Offset="0.375"/>
<GradientStop Color="#FF138B93" Offset="0.625"/>
<GradientStop Color="#FF138B93" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<Grid>
<!--<Rectangle Fill="#FF138B93" Margin="0,0,0,-2"/>-->
<ContentControl x:Name="HeaderTopSelected" FontSize="{TemplateBinding FontSize}" FontWeight="SemiBold" Foreground="{TemplateBinding Foreground}" IsTabStop="False" Cursor="{TemplateBinding Cursor}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalAlignment}"/>
</Grid>
</Border>
</Border>
<Border x:Name="FocusVisualTop" Margin="-2,-2,-2,0" IsHitTestVisible="false" Visibility="Collapsed" BorderBrush="#FF45D6FA" BorderThickness="1,1,1,0" CornerRadius="3,3,0,0"/>
<Border x:Name="DisabledVisualTopSelected" Margin="-2,-2,-2,0" IsHitTestVisible="false" Opacity="0" Background="#8CFFFFFF" CornerRadius="3,3,0,0"/>
</Grid>
<Grid x:Name="TemplateTopUnselected" Visibility="Collapsed">
<Border x:Name="BorderTop" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1" CornerRadius="3,3,0,0">
<Border x:Name="GradientTop" BorderBrush="#FFFFFFFF" BorderThickness="1" CornerRadius="1,1,0,0">
<Border.Background>
<LinearGradientBrush EndPoint=".7,1" StartPoint=".7,0">
<GradientStop Color="#FFFFFFFF" Offset="0"/>
<GradientStop Color="#FF94BFB5" Offset="0.375"/>
<GradientStop Color="#FF94BFB5" Offset="0.625"/>
<GradientStop Color="#FF94BFB5" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<Grid>
<ContentControl x:Name="HeaderTopUnselected" FontSize="{TemplateBinding FontSize}" FontWeight="SemiBold" Foreground="{TemplateBinding Foreground}" IsTabStop="False" Cursor="{TemplateBinding Cursor}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalAlignment}"/>
</Grid>
</Border>
</Border>
<Border x:Name="DisabledVisualTopUnSelected" IsHitTestVisible="false" Opacity="0" Background="#8CFFFFFF" CornerRadius="3,3,0,0"/>
</Grid>

Basically all you have to do to get great looking TabControl like this is to change few properties in default template and that is it.

 

7. Summary

Silverlight have couple nice things to make our life easier when we skinning and styling our controls. If we just want to make minor modifications to our control than we can do it directly in XAML of control by changing few properties. If we want to completely change look and feel of our control and maybe change control behavior than we can do it by changing control default template as save it as our new template. VisualStateManager and Parts Model is nice and easy way to define and change template. VisualStateManager makes it easier to work with states which is a pretty useful when working with controls. Adding control parts in template is also nice way to separate different objects in the template. Expression Blend helps us to work with parts by providing a list of parts in the Parts panel when we are editing a template.

And what is most important we did not have to change any code in our application, nor modify the XAML markup on our actual control, in order to make this nice look of our control.

About author

Radenko Zec work as senior software developer at Lanaco. He is winner of third place in Europian Silverlight Challenge. He is also running local Ineta user group and speaks regularly on local and regional conferences and events. You can read his blog on http://blog.developers.ba/

Share


Comments

Comments RSS RSS
  • RE: Skinning and Styling Silverlight Controls  

    posted by thexray on Jan 12, 2010 17:39
    Is it possible to use styles to change font color on state change?

Add Comment

 
 

   
  
  
   
Please add 6 and 4 and type the answer here:

Help us make SilverlightShow even better and win a free t-shirt. Whether you'd like to suggest a change in the structure, content organization, section layout or any other aspect of SilverlightShow appearance - we'd love to hear from you! Need a material (article, tutorial, or other) on a specific topic? Let us know and SilverlightShow content authors will work to have that prepared for you. (hide this)