样式WPF正常控制取决于Windows主题

时间:2013-04-03 22:32:24

标签: wpf styles themes resourcedictionary windowsversion

我已经阅读了很多关于WPF主题,皮肤,风格等的东西...但是仍然有一些我无法实现的东西。

我有自定义控件,根据操作系统主题设置样式,在每个主题文件(Aero.NormalColor.xaml,Luna.NormalColor.xaml或Aero2.NormalColor.xaml)中使用不同的样式,这项工作喜欢魅力。

我没有在我的App.xaml中加载/强制任何主题,每个控件(如按钮)都会根据操作系统主题保留样式。 所以我看到XP上的XP按钮,Windows 7上的Win7按钮和Windows 8上的Win8按钮。

我还有在App.xaml中加载的ResourceDictionaries,它包含不同普通wpf控件的“named”(显式x:Key)样式。它们看起来像这样:

<Style x:Key="BlackComboBox" TargetType="{x:Type ComboBox}"></Style>

我就像这样使用它们

<ComboBox Style="{StaticResource BlackComboBox}"></ComboBox>

所以现在,我的BlackComboBox在每个Windows(XP / 7/8)上都是一样的。

我尝试实现的是根据操作系统主题为这些普通控件设置不同的样式,而不必对控件进行子类化(我认为为每个需要特定操作系统的控件创建一个子类会有点过分。他们),所以每个操作系统上的BlackComboBox可能会有所不同。

我已经尝试在主题文件中添加具有相同键的样式,但这似乎不起作用。

我考虑过在运行时加载一个不同的ResourceDictionary,其中包含所需操作系统版本的样式:

  • 但它看起来像一个丑陋的解决方案。
  • 我不想检查System.Environment.OSVersion。
  • 它不会依赖于主题,但依赖于操作系统。

对我来说,最好的方法似乎是能够在主题文件中使用“命名”样式,这样可以覆盖ResourceDictionaries中的那个。

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

我认为,实现这一目标的唯一方法是为每个主题创建资源字典,就像创建自定义控件并希望每个主题具有不同外观一样。然后,您将为每个ComboBox创建一个Style,并提供一个ResourceKey派生类(例如ComponentResourceKey)作为Style的x:Key,在每个主题的资源字典中使用相同的x:Key值。然后,当您引用Style时,您将使用DynamicResource到该ResourceKey。

因此,一个简化的例子是创建一个新的WpfApplication(例如我将其命名为WpfResourceKeys)。在这种情况下,我将主题资源字典放在主程序集中,所以我进入 AssemblyInfo.cs 并设置 ThemeInfo 的第一个参数(即 themeDictionaryLocation )到 SourceAssembly

然后创建一个名为“ themes ”的文件夹,并在其中为您要支持的每个主题创建一个资源字典。例如。 aero.normalcolor.xaml aero2.normalcolor.xaml luna.normalcolor.xaml classic.xaml ,等等。

在每个ResourceDictionary中为ComboBox定义一个Style或您想要的任何控件,并为它提供相同ResourceKey的 x:Key 。最简单的方法是使用 ComponentResourceKey 。在我的情况下,我将使用TextBox,因为我将设置背景,无论为每个主题定义的模板如何,都将受到尊重。 E.g。

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:local="clr-namespace:WpfResourceKeys"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style TargetType="TextBox" 
        x:Key="{ComponentResourceKey 
            ResourceId=Foo, 
            TypeInTargetAssembly={x:Type local:MainWindow}}">
        <Setter Property="Background" Value="Purple" />
    </Style>
</ResourceDictionary>

在我的情况下,我只是将它放入每个主题xaml文件中,但背景设置器的值不同,以测试它。所以在我的aero2.normalcolor.xaml中,setter值为Purple,而在classic.xaml中,setter值为Orange。当我在Windows 8中使用默认主题运行我的测试时,TextBox是紫色的,但如果我切换到高对比度主题之一,TextBox就是橙色。

然后在你要引用它的地方,你将使用DynamicResource而不是StaticResource,因为你不会在窗口或app.xaml的资源中定义Style(因为你希望框架找到它)考虑操作系统主题。)

<Window x:Class="WpfResourceKeys.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfResourceKeys"
    Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBox Style="{DynamicResource ResourceKey={ComponentResourceKey 
            ResourceId=Foo, 
            TypeInTargetAssembly={x:Type local:MainWindow}}}" Text="ABC" />
    </Grid>

您只需确保使用等效资源键来定义主题词典中的定义方式。在ComponentResourceKey的情况下,这意味着ResourceId和TypeInTargetAssembly是等效的。