覆盖重写的WPF主题

van*_*ja. 11 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);
}
Run Code Online (Sandbox Code Playgroud)

它主要工作得很好.当我使用按钮等控件时:

<Button />
Run Code Online (Sandbox Code Playgroud)

样式看起来很好,但如果我使用具有不同样式的Button,如下所示:

<Button>
  <Button.Style>
    <Style TargetType="Button">
      <Setter Property="Width" Value="80" />
    </Style>
  </Button.Style>
</Button>
Run Code Online (Sandbox Code Playgroud)

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

Ray*_*rns 10

为什么会这样

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

如何解决它

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

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

<Style TargetType="Button" BasedOn="{DefaultAeroStyle Button}"> ...
Run Code Online (Sandbox Code Playgroud)

您的自定义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>
Run Code Online (Sandbox Code Playgroud)

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

<Style TargetType="Button" BasedOn="{StaticResource ThemeButtonStyle}" />
Run Code Online (Sandbox Code Playgroud)

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