简体   繁体   English

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

[英]Style WPF normal Control depending on Windows Theme

I have read lots of thing about WPF Theme, Skin, Style etc... But there is still something I cannot achieve. 我已经阅读了很多关于WPF主题,皮肤,风格等的东西...但是仍然有一些我无法实现的东西。

I have custom controls, which are styled depending on the OS theme, by having a different style in each of the theme file (Aero.NormalColor.xaml, Luna.NormalColor.xaml or Aero2.NormalColor.xaml), this work like a charm. 我有自定义控件,根据操作系统主题设置样式,在每个主题文件(Aero.NormalColor.xaml,Luna.NormalColor.xaml或Aero2.NormalColor.xaml)中使用不同的样式,这个工作就像一个魅力。

I don't load/force any theme in my App.xaml, each controls (like buttons) keep there style depending on the OS theme. 我没有加载/强制我的App.xaml中的任何主题,每个控件(如按钮)保持样式取决于操作系统主题。 So I see XP buttons on XP, Win7 buttons on windows 7 and Win8 buttons on Windows 8. 所以我看到XP上的XP按钮,Windows 7上的Win7按钮和Windows 8上的Win8按钮。

I also have ResourceDictionaries which are loaded in the App.xaml that contains "named" (explicit x:Key) styles for different normal wpf controls. 我还有在App.xaml中加载的ResourceDictionaries,它包含不同普通wpf控件的“命名”(显式x:Key)样式。 They look like this: 它们看起来像这样:

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

and I use them like this 我就像这样使用它们

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

So for now, my BlackComboBox is the same on every Windows (XP/7/8). 所以现在,我的BlackComboBox在每个Windows(XP / 7/8)上都是一样的。

What I try to achieve is to have a different Style for these normal Controls depending on the OS theme, without having to subclass the Control (I think it will be overkill to have a subclass for each control that will need an OS specific them), so BlackComboBox could be different on each OS. 我试图实现的是根据操作系统主题为这些普通控件设置不同的样式,而不必对控件进行子类化(我认为为每个需要特定操作系统的控件创建一个子类会有点过分),所以BlackComboBox在每个操作系统上都可能不同。

I have already tried to put a style with the same key in a theme file, but this doesn't seem to work. 我已经尝试在主题文件中添加具有相同键的样式,但这似乎不起作用。

I have thought about loading at runtime a different ResourceDictionary containing the style for the desired OS version: 我想过在运行时加载一个包含所需操作系统版本样式的不同ResourceDictionary:

  • But it looks like an ugly solution. 但它看起来像一个丑陋的解决方案。
  • I don't like having to check for System.Environment.OSVersion. 我不喜欢检查System.Environment.OSVersion。
  • And it will not be theme dependant, but OS dependent. 它不会依赖于主题,而是依赖于操作系统。

For me the best way seems to be able to have "named" style in a Theme file that kind of overrides the one in the ResourceDictionaries. 对我来说,最好的方法似乎是能够在主题文件中使用“命名”样式,这样可以覆盖ResourceDictionaries中的那个。

Thanks for the help! 谢谢您的帮助!

I believe the only way to do this would be to create resource dictionaries for each theme the same you would if you created a custom control and wanted to have a different look for each theme. 我相信这样做的唯一方法是为每个主题创建资源字典,就像创建自定义控件并希望每个主题具有不同的外观一样。 Then you would create a Style in each for the ComboBox and provide a ResourceKey derived class (eg ComponentResourceKey) as the x:Key for the Style using the same value for the x:Key in each theme's resource dictionary. 然后,您将为每个ComboBox创建一个Style,并提供一个ResourceKey派生类(例如ComponentResourceKey)作为Style的x:Key,在每个主题的资源字典中使用相同的x:Key值。 Then when you reference the Style you would use a DynamicResource to that ResourceKey. 然后,当您引用Style时,您将使用DynamicResource到该ResourceKey。

So a simplified example would be to create a new WpfApplication (eg I named its WpfResourceKeys). 因此,一个简化的例子是创建一个新的WpfApplication(例如我将其命名为WpfResourceKeys)。 In this case I'm going to put the theme resource dictionaries in the main assembly so I go into the AssemblyInfo.cs and set the ThemeInfo 's 1st parameter (ie the themeDictionaryLocation ) to SourceAssembly . 在这种情况下,我将把主题资源字典放在主程序集中,所以我进入AssemblyInfo.cs并将ThemeInfo的第一个参数(即themeDictionaryLocation )设置为SourceAssembly

Then create a folder named " themes " and in it create a resource dictionary for each theme you want to support.Eg aero.normalcolor.xaml , aero2.normalcolor.xaml , luna.normalcolor.xaml , classic.xaml , etc.. 然后创建一个名为“ themes ”的文件夹,并在其中为您要支持的每个主题创建一个资源字典.Eg aero.normalcolor.xamlaero2.normalcolor.xamlluna.normalcolor.xamlclassic.xaml等。

In each ResourceDictionary define a Style for ComboBox or whatever control you want and give it an x:Key of the same ResourceKey. 在每个ResourceDictionary中为ComboBox定义一个Style或你想要的任何控件,并给它一个相同ResourceKey的x:Key The easiest thing to use is ComponentResourceKey . 最简单的方法是使用ComponentResourceKey In my case I'll use a TextBox since I'll just set the Background and that will be honored regardless of the template defined for each theme. 在我的情况下,我将使用TextBox,因为我将设置背景,无论为每个主题定义的模板如何,都将受到尊重。 Eg 例如

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

In my case I just put this into each theme xaml file but with a different value for the Background setter to test it out. 在我的情况下,我只是把它放到每个主题xaml文件中,但背景设置器的值不同,以测试它。 So in my aero2.normalcolor.xaml the setter value was Purple and in the classic.xaml the setter value was Orange. 所以在我的aero2.normalcolor.xaml中,setter值为Purple,而在classic.xaml中,setter值为Orange。 When I run my test in Windows 8 with the default theme the TextBox is purple but if I switch to one of the high contrast themes the TextBox is Orange. 当我在Windows 8中使用默认主题运行我的测试时,TextBox是紫色的,但如果我切换到高对比度主题之一,TextBox就是橙色。

Then in the place you are going to reference it you would use a DynamicResource instead of a StaticResource since you won't be defining the Style within the resources of the window or app.xaml (because you want the framework to locate it considering the OS theme). 然后在你要引用的地方你将使用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>

You just need to make sure you use an equivalent resource key to how you define it in the theme dictionaries. 您只需确保使用等效资源键来定义主题词典中的定义方式。 In the case of ComponentResourceKey that means the ResourceId and TypeInTargetAssembly are equivalent. 在ComponentResourceKey的情况下,这意味着ResourceId和TypeInTargetAssembly是等效的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM