覆盖重写的WPF主题

时间:2010-03-04 05:21:53

标签: wpf

我正在WinXP上编写一个WPF应用程序,我用这样的vista主题覆盖了默认主题:

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);
}

它的工作原理很好。当我使用按钮等控件时:

<Button />

样式看起来很好,但是如果我使用具有不同风格的Button:

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

该样式将使用标准的WinXP样式覆盖指定的主题样式,而不是在其上构建。这对我来说是非常有限的。有没有办法避免这个问题?

1 个答案:

答案 0 :(得分:10)

为什么会这样?

使用当前主题的资源字典生成样式的默认BasedOn =。您为覆盖主题而显示的技术实际上并未更改正在使用的主题词典:它只是将主题资源字典中的资源添加到应用程序的资源字典中。由于当前主题未更改,因此默认的BasedOn也保持不变。

如何解决

选项1:通过拦截对Win32级别的uxtheme.dll!GetCurrentThemeName的调用来本地覆盖主题。这非常复杂,但适用于所有样式而不会更改XAML。

选项2:使用自定义MarkupExtension设置BasedOn。它看起来像这样:

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

您的自定义MarkupExtension会在首次使用时加载Aero主题词典并将其存储在静态字段中。它的构造函数将采用Type,其ProvideValue将在字典中查找类型以查找样式。

选项3:将BasedOn设置为中间命名样式。它看起来像这样:

<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>

现在在您的低级词典中,您可以说:

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

选项4:使用静态属性和x:静态标记扩展

设置BasedOn