Microsoft introduced the concept of “lookless” controls in WPF, which means that the control defines its behaviour without any information about how it actually looks, which is where templates and styles come in. However, all of the default controls provide a default look, which is in keeping with the current Windows theme (Aero in Windows Vista, Luna, Metallic, or Homestead in Windows XP and so on). If you are creating lookless controls in a class library for general consumption, it would be helpful to also provide a default look for your controls. To achieve this, there are three things that you need to do.

Note: This article refers specifically to custom controls (i.e., those that inherit from ControlFrameworkElement or similar, not user controls that inherit from UserControl). For more information about creating controls for WPF, see Control Authoring Overview on the MSDN web site.

1. Override the Metadata for the DefaultStyleKey Property

In a static constructor for your control, set the default style key to the type name, which is used to do style lookups for your control. The following code example shows the static constructor for a Wizard class that I’m creating.

1:  static Wizard()
2:  {
3:      DefaultStyleKeyProperty.OverrideMetadata(
4:          typeof(Wizard),
5:          new FrameworkPropertyMetadata(typeof(Wizard)));
6:  }

2. Define Your Default Style

You can create a default style in WPF Developer Training for each of the different Windows themes. To do this, you need to create resource dictionary with a specific name in a Themes folder that is a subfolder of the folder that contains your control in your class library. The following table provides the file names of the theme-specific resource dictionaries.

Resource dictionary Windows theme
Classic.xaml “Classic” Windows 9x/2000 look on Windows XP
Luna.NormalColor.xaml Default blue theme on Windows XP
Luna.Homestead.xaml Olive theme on Windows XP
Luna.Metallic.xaml Silver theme on Windows XP
Royale.NormalColor.xaml Default theme on Windows XP Media Center Edition
Aero.NormalColor.xaml Default theme on Windows Vista

You don’t need to provide a style for every theme. If there is no theme-specific resource, then the generic resource is used for the control, which is defined in the Themes\generic.xaml resource dictionary.

The following XAML code example shows the default style in generic.xaml for the Wizard class described above:

1:  <ResourceDictionary xmlns="schemas.microsoft.com/.../presentation"
 2:                      xmlns:local="clr-namespace:DerekLakin.Libraries.Presentation"
 3:                      xmlns:x="schemas.microsoft.com/.../xaml">
 4:      <Style TargetType="{x:Type local:Wizard}">
 5:          <Setter Property="Template">
 6:              <Setter.Value>
 7:                  <ControlTemplate TargetType="{x:Type local:Wizard}">
 8:                      <DockPanel LastChildFill="True">
 9:                          <WrapPanel DockPanel.Dock="Bottom"
10:                                     HorizontalAlignment="Right"
11:                                     Orientation="Horizontal"
12:                                     Margin="10">
13:                              <Button x:Name="PART_Back"
14:                                      Content="Back" />
15:                              <Button x:Name="PART_Next"
16:                                      Content="Next"
17:                                      Margin="4,0,0,0" />
18:                              <Button x:Name="PART_Cancel"
19:                                      Content="Cancel"
20:                                      Margin="4,0,0,0" />
21:                              <Button x:Name="PART_Finish"
22:                                      Content="Finish"
23:                                      Margin="4,0,0,0" />
24:                          </WrapPanel>
25:                          <Frame x:Name="PART_Frame"
26:                                 NavigationUIVisibility="Hidden" />
27:                      </DockPanel>
28:                  </ControlTemplate>
29:              </Setter.Value>
30:          </Setter>
31:      </Style>
32:  </ResourceDictionary>

3. Add the ThemeInfo Attribute to AssemblyInfo

The final part is to publicise the fact that your assembly contains control-specific resources, which you do by using the ThemeInfo attribute. The GenericDictionaryLocation property defines where the generic resources are and the ThemeDictionaryLocation property defines where the themed resources are. The value for both properties is a ResourceDictionaryLocation enumeration, which is None, SourceAssembly, or ExternalAssembly.

The following code example shows the ThemeInfo attribute for the class library project that contains the Wizard class described previously, which has no theme-specific resources, but does specify a generic resource.

1:  [assembly: ThemeInfo(ResourceDictionaryLocation.None,
2:      ResourceDictionaryLocation.SourceAssembly)]