Silverlight and styles
This post is the result of a couple of frustrating moments passed yesterday. In our application we use the date picker control of the Silverlight toolkit. Unfortunately this control does not work exactly as we would like to thus I decided to redefine its template such as that the control better fits our needs. I didn’t want to put the new style into the app.xaml file but rather store it as a resource in the assembly where our new and improved date picker resides.
The generic.xaml
The documentation about how this is to be done is incomplete at best. After Google-ing I quickly found out that we can put the styles in a file called generic.xaml; e.g. something like this
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:MyNamespace"
>
<Style TargetType="controls:SampleButton">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:SampleButton">
<Border CornerRadius="2"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary></p>
Note that the above is just a sample style that I used to experiment with. The style for the date picker is much more complex.
In the constructor of my sample control I then just have to put this assignment
public SampleButton()
{
DefaultStyleKey = typeof(SampleButton);
}</p>
Ok, nice, so did I. But my application didn’t work any more; the style was not picked up as before (when it was defined in the app.xaml). After some more Google-ing I found out that the Build Action of the generic.xaml has to be of type Resource. Still no success. My custom control did not pick up the style.
Still more Google-ing was needed and some consumption of videos on the official Silverlight site. The next piece of information I got was that the generic.xaml file has to reside in a folder called Themes. Hurray, finally my custom control worked.
Merging resources
Well, now if we have many custom controls with many different styles and other resources the generic.xaml file quickly gets crowded too. Luckily there exists a possibility how one can merge the generic.xaml from different sources. Thus I can define my styles for different controls in individual resource files. The syntax for this is
<ResourceDictionary
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/FluentSilverlight;component/Themes/FsDatePicker.xaml"/>
<ResourceDictionary Source="/FluentSilverlight;component/Themes/FsComboBox.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary></p>
It is very important to note that there is an inconsistency in the way merge dictionaries are defined in the app.xaml and in the generic.xaml. Where in the former case the attribute Source of the tag ResourceDictionary is a relative URI in the latter Source must be an absolute URI and has the following structure
<ResourceDictionary Source="/assemblyName;component/path/fileName.xaml"></p>
Where assemblyName is the name of the assembly where the xaml file is contained; component is a keyword; path is the path to the file and fileName is the name of the xaml file to merge. So in the above sample the assembly is FluentSilverlight and the two xaml files reside in a folder inside the project called Themes
Meaningful Exception text anybody?
One of the most annoying factors with Silverlight is that its exception texts are often pretty useless. If there is a mistake in the definition of a template you get a very cryptic error message. Some more love from Microsoft regarding exceptions would be highly appreciated.