如何扩展而不是覆盖 WPF 样式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15576589/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 08:15:31  来源:igfitidea点击:

How to extend instead of overriding WPF Styles

wpfstylesthemesskinbasedon

提问by labm0nkey

I want to use custom theme in my application and as far as I know I can accomplish this by using resource dictionary and referencing it in App.xaml. Styles would override the defaults like this:

我想在我的应用程序中使用自定义主题,据我所知,我可以通过使用资源字典并在 App.xaml 中引用它来实现这一点。样式会像这样覆盖默认值:

<Style TargetType="{x:Type Label">
    <Setter Property="Foreground" Value="Green" />
</Style>

Now as I guess the default Label style is overriden with same values but all my label fonts are green. The problem starts when I want to style one label somewhere again. When I want to change some other property in my Grid like this

现在我猜默认标签样式被相同的值覆盖,但我所有的标签字体都是绿色的。当我想再次在某处设置一个标签的样式时,问题就开始了。当我想像这样更改网格中的其他属性时

<Grid.Resources>
    <Style TargetType="{x:Type Label">
        <Setter Property="FontSize" Value="28" />
    </Style>
</Grid.Resources>

All labels inside my grid are losing their foreground color and have default one again (didn't I override defaults in previous step?). After some tries I found out that to do this properly i have to add another property to Styledeclaration BasedOn={StaticResource {x:Type Label}}"and it works. This is kind of weird for me because now I will have to repeat same BasedOn code in whole app and this is not how styling works - this should be done automatically! For example in HTML + CSS styles are inherited and merged and in WPF they are replaced...

我的网格中的所有标签都失去了前景色并再次使用默认值(我在上一步中没有覆盖默认值吗?)。经过一些尝试,我发现要正确执行此操作,我必须向Style声明添加另一个属性,BasedOn={StaticResource {x:Type Label}}"并且它可以工作。这对我来说有点奇怪,因为现在我必须在整个应用程序中重复相同的 BasedOn 代码,这不是样式的工作方式 - 这应该自动完成!例如,在 HTML + CSS 样式中继承和合并,而在 WPF 中它们被替换......

Notice that when I don't use any styles controls still get their look from somehwere (System Themes?). How can I tell them to look for defaults somewhere else so without any additional code on styles they will think that they should be green by default?

请注意,当我不使用任何样式时,控件仍然会从某个地方(系统主题?)获得它们的外观。我怎样才能告诉他们在其他地方寻找默认值,所以没有任何关于样式的额外代码,他们会认为默认情况下它们应该是绿色的?

Is there any way I can automate setting BasedOn property? Or maybe there is a better to do this overally?

有什么方法可以自动设置 BasedOn 属性吗?或者也许有更好的方法来做到这一点?

回答by Baptiste

I had the same problem. I used Zack's answer and improved it like following so if you don't specify a style the overridden default is still taken in account. It's basically what you would have done but just once in the ResourceDictionary.

我有同样的问题。我使用了 Zack 的答案并对其进行了改进,如下所示,因此如果您不指定样式,则仍会考虑覆盖的默认值。这基本上是你会做的,但在 ResourceDictionary 中只有一次。

<Window x:Class="TestWpf.RandomStuffWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Random Stuff Window">
  <Window.Resources>
    <ResourceDictionary>
      <!-- Default Label style definition -->
      <Style TargetType="{x:Type Label}">
        <Setter Property="Foreground" Value="Green" />
      </Style>
      <!-- Extending default style -->
      <Style TargetType="{x:Type Label}" 
             x:Key="LargeGreenForegroundLabel" 
             BasedOn="{StaticResource {x:Type Label}}">
        <Setter Property="FontSize" Value="28" />
      </Style>
    </ResourceDictionary>
  </Window.Resources>
  <StackPanel>
    <Button Click="Button_Click">Click</Button>
    <Label Content="GreenForegroundLabel" /> <!-- Uses default style -->
    <Label Style="{StaticResource LargeGreenForegroundLabel}" 
           Content="LargeGreenForegroundLabel" />
  </StackPanel>
</Window>

回答by Zack

Wpf has different levels of styles, that are applied in order of global > local. A style set directly on a control will override a style set globally, like in your example. I was trying to find a list of all the different places that a control looks for its styles but I cannot find one at the moment. As far as I know, you will have to use the BasedOn property to inherit a style and not completely override the properties of that style with the style you set locally.

Wpf 具有不同级别的样式,按全局 > 局部的顺序应用。直接在控件上设置的样式将覆盖全局样式集,就像在您的示例中一样。我试图找到控件寻找其样式的所有不同位置的列表,但目前我找不到。据我所知,您必须使用 BasedOn 属性来继承样式,而不是使用您在本地设置的样式完全覆盖该样式的属性。

Here is an example of a resource dictionary that has styles based on another style, so that you don't have do repeat the BasedOnbinding over and over, you can just set the style on the specific element you want to have that style.

这是一个资源字典的示例,它具有基于另一种样式的样式,因此您不必一遍BasedOn又一遍地重复绑定,您只需在要具有该样式的特定元素上设置样式即可。

<Window x:Class="TestWpf.RandomStuffWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Random Stuff Window">
  <Window.Resources>
    <ResourceDictionary>
      <Style TargetType="{x:Type Label}" 
             x:Key="GreenForegroundLabel">
        <Setter Property="Foreground" Value="Green" />
      </Style>
      <Style TargetType="{x:Type Label}" 
             x:Key="LargeGreenForegroundLabel" 
             BasedOn="{StaticResource GreenForegroundLabel}">
        <Setter Property="FontSize" Value="28" />
      </Style>
    </ResourceDictionary>
  </Window.Resources>
  <StackPanel>
    <Button Click="Button_Click">Click</Button>
    <Label Style="{StaticResource GreenForegroundLabel}" 
           Content="GreenForegroundLabel" />
    <Label Style="{StaticResource LargeGreenForegroundLabel}" 
           Content="LargeGreenForegroundLabel" />
  </StackPanel>
</Window>