【问题标题】:Override Overridden WPF Theme覆盖覆盖的 WPF 主题
【发布时间】:2011-01-23 12:56:28
【问题描述】:

我正在 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.Style>
    <Style TargetType="Button">
      <Setter Property="Width" Value="80" />
    </Style>
  </Button.Style>
</Button>

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

【问题讨论】:

    标签: wpf


    【解决方案1】:

    为什么会这样

    样式的默认 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:Static 标记扩展设置 BasedOn

    【讨论】:

    • 谢谢,您的回答真的很有帮助。 WPF 中似乎缺少这个区域。您通常使用哪个选项来解决此问题?
    • 选项 2 很酷,在某种程度上它甚至解决了不能使用 BasedOn DynamicResources 的问题。
    • 我通常通过向客户解释最好坚持使用当前操作系统主题来解决问题,因为窗口对于最终用户来说看起来“正常”。但是,在我需要重新设置 UI 的一部分但 UI 的内部部分(例如弹出窗口)重新设置样式的情况下,我使用了选项 2 和选项 3。跨度>
    • 我知道不覆盖 Windows 主题是一个更好的选择 - 但如果我使用的是完全自定义的主题怎么办?那会遇到同样的问题。
    • 如果您使用的是完全自定义的主题,我可能会选择选项 2,因为在您的自定义主题中查找内容会很容易。
    猜你喜欢
    • 2011-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-11
    • 2020-03-27
    • 2022-01-15
    • 1970-01-01
    相关资源
    最近更新 更多