3

我已经阅读了很多关于 WPF 主题、皮肤、样式等的内容......但仍有一些我无法实现的东西。

我有自定义控件,它们的样式取决于操作系统主题,通过在每个主题文件(Aero.NormalColor.xaml、Luna.NormalColor.xaml 或 Aero2.NormalColor.xaml)中具有不同的样式,这就像一个魅力.

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

我还有 ResourceDictionaries 加载在 App.xaml 中,其中包含不同普通 wpf 控件的“命名”(显式 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 中的样式。

谢谢您的帮助!

4

1 回答 1

1

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

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

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

在每个 ResourceDictionary 中,为 ComboBox 或任何您想要的控件定义一个样式,并为其提供相同 ResourceKey 的x:Key。最容易使用的是ComponentResourceKey。在我的情况下,我将使用 TextBox,因为我将设置背景,并且无论为每个主题定义的模板如何,都会得到尊重。例如

<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 的资源中定义样式(因为您希望框架在考虑操作系统的情况下找到它主题)。

<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 是等价的。

于 2013-05-29T13:24:58.513 回答