Friday, November 28, 2008

Setting up Theme-Specific Resource Dictionaries

Configuring theme-specific resource dictionaries is a common stumbling block. Follow these rules to ensure they are set up correctly:

  • 1. In the AssemblyInfo for your assembly, set the ThemeInfo attribute. This will specify where the theme-specific and generic resource dictionaries for the styleable resources referenced and defined in the assembly can be found.
  • [assembly: ThemeInfo(
        ResourceDictionaryLocation.SourceAssembly, 
        // Where theme-specific resource dictionaries are located.
        // (Used if a resource is not found in the page, 
        // or application resource dictionaries.)
     
        ResourceDictionaryLocation.SourceAssembly 
        // Where the generic resource dictionary is located.
        // (Used if a resource is not found in the page, 
        // app, or any theme specific resource dictionaries.)
    )]
    
  • 2. Put your theme-specific resource dictionaries in the Themes folder of the relevant assembly so they will be automatically picked up (do not use LoadComponent). Also add a generic resource dictionary with the name generic.xaml.



  • 3. Any control-specific theme-specific resource dictionaries should also be added to the Themes folder. The dictionary should then be merged into a main resource dictionary like this:
  • <!-- Aero.NormalColor.xaml: -->
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary
            Source="/MyAssemblyName;component/Themes/MyControl.Aero.NormalColor.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    
  • 4. Do the same with any control-specific generic resource dictionaries:
  • <!-- generic.xaml: -->
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary
            Source="/MyAssemblyName;component/Themes/UnthemedControl.generic.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    
  • 5. Any resources defined in your assembly required to pick up styles from the theme-specific or generic resource dictionaries should override the default style key in their static constructor. You should also do this if you want to override the default style of the base class of the resource.
  • // Register the default style for MyControl.
    DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl), 
        new FrameworkPropertyMetadata(typeof(MyControl)));
    
  • 6. If you want to set the style of a control not defined in your assembly, you will need to explicitly load the resource dictionary:
  • ResourceDictionary dict = Application.LoadComponent(
        new Uri("MyAssemblyName;component/Themes/NewDefaultStyle.xaml", UriKind.Relative))
        as ResourceDictionary;
    
    Application.Current.Resources.MergedDictionaries.Add(dict);
    
    
    ...and that's it! That should cover everything you need to do to get your resources picking up their styles from the correct place.

    Download Full Source Code



    3 comments:

    Pat Malone said...

    I am having this problem as well. Unfortunately I am a novice at WPF and cannot get you example to compile and run. Do you have the as complete example code instead of snippets. Thanks.

    WPF Mentor said...

    I've added an example solution to the post.

    Thanks

    John said...

    Thank you very much!! I wasted hours trying to figure this out on my own, your article was a great help.