I’ve been looking for a way the use themes just swapping ResourceDictionaries (RD’s) for some time. Now, with Silverlight 3 being able to use MergedDictionaries, this becomes possible.
It’s still not Blendable, because Blend can only use RD’s with Build Action Resource and not Content. This is annoying enough to give it another go another time. You can use the workaround of having a copy of the default RD in your App.xaml file or using a different RD with build action as Resource for use with Blend only. Want you ultimately want is to address the RD’s as Resource…
This method can help you when you:
- want to load a theme once on application startup
- want to set the theme as an initParam on the Silverlight plug-in
- don’t want to use implicit styling: you’ll need two or more RD’s with identically named Styles and Resources
Restrictions of this method are:
- Not Blendable (yet), but workarounds exist
- You have to use one Default theme (which can have any name you want).
- You cannot dynamically update the theme: you can set a certain theme only once at application startup.
If this is the method for you, this is what you need to do:
- Create ResourceDictionaries for the Default Theme and for one or more other Themes that you want to load in the root of your Silverlight project. Use x:Keys for Styles and Resources and keep them the same between RD’s. Set the Build Action for these RD’s to CONTENT in Visual Studio or by editing your .CSPROJ file by hand.
- Insert an initParam in the <Object> tag in your startup file:
[sourcecode language="XML"]
<param name="initParams" value="Theme=TheTheme" />
[/sourcecode]
- Add a Default MergedDictionary in App.xaml:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Default.xaml"/>
</ResourceDictionary.MergedDictionaries>
- Declare a private currentTheme variable in App.xaml.cs
public partial class App : Application
{
private string currentTheme = "Default";
…
- Set the Default theme, get the initParam, make an URL to the filename and create and RD from that. Then add the RD to the MergedDictionaries:
private void Application_Startup(object sender, StartupEventArgs e)
{
//set the current theme to the currentTheme variable
string currentThemeName = string.Format("{0}.xaml", currentTheme);
//get the theme name from the initParam
string themeParameter = e.InitParams["Theme"];
if (!string.IsNullOrEmpty(currentThemeString))
{
//set the current theme to the theme parameter and create filename
currentThemeName = string.Format("{0}.xaml", themeParameter);
//create an URL from the currentThemeName
Uri themeUrl = new Uri(currentThemeName, UriKind.RelativeOrAbsolute);
try
{
//create a RD and set the source to the URL
ResourceDictionary themeDictionary = new ResourceDictionary
{
Source = themeUrl
};
//Add the RD as a MergedDictionary
Application.Current.Resources.MergedDictionaries.Add(themeDictionary);
}
catch (Exception ex)
{
//communicate theme doesn’t exist
throw;
}
}
this.RootVisual = new MainPage();
}
Many thanks to Tony Tromp and Michaud Venant for helping me out with the code.
Njoy!