11

I am writing a WPF application on WinXP and I have overridden the default theme with the vista theme like this:

protected override void OnStartup(StartupEventArgs e)
{
  base.OnStartup(e);

  var themerd = new ResourceDictionary();
  themerd.Source = new Uri(@"PresentationFramework.Aero;V3.0.0.0;31bf3856ad364e35;component\themes/aero.normalcolor.xaml", UriKind.Relative);

  Resources.MergedDictionaries.Add(themerd);
}

And it works fine mostly. When I use control such as a button:

<Button />

The style looks fine, but if I use a Button with a different style like this:

<Button>
  <Button.Style>
    <Style TargetType="Button">
      <Setter Property="Width" Value="80" />
    </Style>
  </Button.Style>
</Button>

The style will override the specified theme style with the standard WinXP style instead of building on top of it. This is extremely limiting for me. Is there a way to avoid this issue?

Cœur
  • 37,241
  • 25
  • 195
  • 267
vanja.
  • 2,532
  • 3
  • 23
  • 39

1 Answers1

11

Why this is happening

The default BasedOn= for a style is generated using only the current theme's resource dictionary. The technique you show for overriding a theme doesn't actually change the theme dictionary in use: It simply adds the resources from the theme's resource dictionary to the application's resource dictionary. Since the current theme is unchanged, the default BasedOn is also unchanged.

How to solve it

Option 1: Locally override the theme by intercepting calls to uxtheme.dll!GetCurrentThemeName at the Win32 level. This is quite complex but works for all your styles with no changes to your XAML.

Option 2: Set BasedOn using a custom MarkupExtension. It would look like this:

<Style TargetType="Button" BasedOn="{DefaultAeroStyle Button}"> ...

Your custom MarkupExtension would load the Aero theme dictionary on first use and store it in a static field. Its constructor would take a Type, and its ProvideValue would look up the type in the dictionary to find the style.

Option 3: Set BasedOn to an intermediate named style. It would look like this:

<Application ...>
  <Application.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="... theme path ..." />
      </ResourceDictionary.MergedDictionaries>

      <Style x:Key="ThemeButtonStyle" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}" />
      <Style x:Key="ThemeListBoxStyle" TargetType="ListBox" BasedOn="{StaticResource {x:Type ListBox}}" />
      ...
    </ResourceDictionary>
  </Application.Resources>
</Application>

Now in your lower-level dictionary you can say:

<Style TargetType="Button" BasedOn="{StaticResource ThemeButtonStyle}" />

Option 4: Set BasedOn using a static property and the x:Static markup extension

Ray Burns
  • 62,163
  • 12
  • 140
  • 141
  • 1
    Thanks, your answer was really helpful. This area seems to be lacking in WPF. Which option do you normally use to solve this issue? – vanja. Mar 04 '10 at 06:09
  • Option 2 is very cool, to some extent it even gets around the problem of not being to BasedOn DynamicResources. – vanja. Mar 04 '10 at 07:08
  • I normally solve the issue by explaining to the customer that it is better to stick with the current OS theme because the windows will look "normal" to the end user. However I have used both Option 2 and Option 3 in situations where I need a section of the UI to be restyled but an inner section of the UI (such as a Popup) to *not* be restyled. – Ray Burns Mar 04 '10 at 14:48
  • I understand that not overriding the windows theme is a much better option - but what if I'm using a completely custom theme? That would run into the same problems. – vanja. Mar 05 '10 at 01:21
  • If you're using a completely custom theme, I'd probably go with Option 2, since it will be easy to look things up in your custom theme. – Ray Burns Mar 05 '10 at 07:16
  • Simply adding a BasedOn="{StaticResource {x:Type Button}}" to the local Style definition was enough to make it work for me--thanks for the solution to this it was driving me nuts! – devios1 May 23 '10 at 01:55