Replaceable resources in Silverlight

Some time ago I faced a requirement where I needed to be able override my Silverlight resources at runtime, and here’s how it got implemented.  All the resources that we wanted to be able to override got moved into a specific ResourceDictionary, which was brought into the App.xaml resources through a MergedDictionary.  Then at runtime, the following code would be executed:

public void LoadResourcesFromServer()
{
    DownloadStyle(new Uri("../ClientBin/brand/CustomizableResources.xaml", UriKind.Relative));
}

private void DownloadStyle(Uri downloadUri)
{
    WebClient wc = new WebClient();
    wc.DownloadStringCompleted += ParseAndAddStyles;
    wc.DownloadStringAsync(downloadUri);
}

This is just a pretty standard way of downloading a file.  It starts to get interesting when we process the downloaded XAML file (exception-handling code elided for clarity):

private void ParseAndAddStyles(object sender, DownloadStringCompletedEventArgs e)
{
    if (e.Error == null)
    {
        var loaded = (ResourceDictionary)XamlReader.Load(e.Result);
        MergeResources(loaded);
    }
}

private void MergeResources(ResourceDictionary resourceDictionary)
{
    foreach (ResourceDictionary dictionary in Application.Current.Resources.MergedDictionaries)
    {
        if (dictionary.Source.OriginalString == "CustomizableResources.xaml")
        {
            Application.Current.Resources.MergedDictionaries.Remove(dictionary);
            break;
        }
    }
    Application.Current.Resources.MergedDictionaries.Add(resourceDictionary);
}

This code parses the XAML into a ResourceDictionary, and then replaces the CustomizableResources dictionary that has been compiled into the XAP file with the one downloaded.

As you can imagine, there are a large number of failure cases which need to be considered in real-life (e.g. the web server gives a 404 or other error, the downloaded XAML fails parsing, or isn’t a ResourceDictionary, etc, etc) but this code is at the heart of our solution to the requirement.

July 28 2011
blog comments powered by Disqus