我想将所有元素的前景(文本)颜色设置为特定的颜色。
<Window Foreground="Red">
<Label Content="Test"/>
<Label Content="Test"/>
<CheckBox Content="Checkbox"/>
</Window>
这没有任何效果...唯一能让它起作用的方法是在每个元素上单独设置Foreground属性。如果有数百个元素,等等,这将非常麻烦。
也许你知道其他方法?
这是因为像Label
和CheckBox
这样的控件在它们的样式中覆盖了Foreground
属性。
下面是一个典型逻辑元素树的示例,显示了在树中从Window
级别指定的值如何向下传递:
Window (Red [Local])
-> Grid (Red [Inherited])
-> ListBox (Red [Inherited])
-> ListBoxItem (Red [Inherited])
-> StackPanel (Red [Inherited])
-> Label (Black [Style])
-> TextBlock (Black [Inherited])
-> TextBlock (Red [Inherited])
在方括号中显示值的来源。
如您所见,继承关系在 Label
上被打破,因为它具有默认样式中设置的 Foreground
属性:
<Style x:Key="{x:Type Label}"
TargetType="{x:Type Label}">
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
...
</Style>
为了解决这个问题,我们可以使用以下方法。在应用程序中(在 App.xaml 或 Window
中)定义这些控件(如 Label
)的默认样式。然后在该默认样式中通过覆盖 Foreground
属性来设置一个相对源绑定,以便将其设置为仍具有所需值的控件的最近祖先:
<Style TargetType="{x:Type Label}">
<Setter Property="Foreground"
Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}, Path=(TextElement.Foreground)}"/>
</Style>
<Style TargetType="{x:Type CheckBox}">
<Setter Property="Foreground"
Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}, Path=(TextElement.Foreground)}"/>
</Style>
之后我们的树将会是这个样子:
Window (Red [Local])
-> Grid (Red [Inherited])
-> ListBox (Red [Inherited])
-> ListBoxItem (Red [Inherited])
-> StackPanel (Red [Inherited])
-> Label (Red [Binding to StackPanel.(TextElement.Foreground)])
-> TextBlock (Red [Inherited])
-> TextBlock (Red [Inherited])
正如您所看到的,我们的绑定恢复了继承。
这些样式需要为每个在其样式中覆盖Foreground
属性的元素定义。正如@Duane建议的那样,为了不在每个样式中重复绑定,可以使用BasedOn
功能:
<Style x:Key="ForegroundInheritanceFixStyle"
TargetType="Control">
<Setter Property="Foreground"
Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}, Path=(TextElement.Foreground)}"/>
</Style>
<Style TargetType="{x:Type Label}"
BasedOn="{StaticResource ForegroundInheritanceFixStyle}">
</Style>
<Style TargetType="{x:Type CheckBox}"
BasedOn="{StaticResource ForegroundInheritanceFixStyle}">
</Style>
希望这可以帮到您。遗憾的是,在WPF中,样式的工作方式不允许您在父类上创建通用样式,并将其应用于子类控件。
您可以做的一件事是创建一个基础样式,针对具有您要设置属性的基础类型(如ContentControl),然后为每个控件创建一个特定样式,该样式基于该样式。以下是一个示例:
<Window>
<Window.Resources>
<Style x:Key="BaseContentControlStyle" TargetType="{x:Type ContentControl}">
<Setter Property="Foreground" Value="Red" />
</Style>
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource BaseContentControlStyle}" />
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource BaseContentControlStyle}" />
</Window.Resources>
<StackPanel>
<Label Content="Test"/>
<Label Content="Test"/>
<CheckBox Content="Checkbox"/>
</StackPanel>
</Window>
<Window.Resources>
<Style x:Key="BaseContentControlStyle" TargetType="{x:Type Control}">
<Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}, Path=(TextElement.Foreground)}"/>
</Style>
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource BaseContentControlStyle}" />
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource BaseContentControlStyle}" />
</Window.Resources>
至少这样你就不必在各处复制相同的setter代码了(顺便说一下,我认为TextBlock默认继承;没有默认样式可以覆盖)。
Foreground
属性会被逻辑树中的每个元素继承。只有当该属性在元素本地或样式中设置值时,继承才会停止。在 Label
和 CheckBox
控件中,默认样式继承也会停止。我覆盖了默认样式使其从父级控件中继续继承。如果你不相信,请试一试-它是有效的。 - Pavlo Glazkov在WPF中确实不容易。但你可以尝试这样做
<StackPanel>
<StackPanel.Resources>
<Style x:Key="CommonStyle">
<Setter Property="TextElement.Foreground" Value="Red" />
</Style>
</StackPanel.Resources>
<Label Content="Test" Style="{StaticResource CommonStyle}" />
<Label Content="Test" Style="{StaticResource CommonStyle}"/>
<CheckBox Content="Checkbox" Style="{StaticResource CommonStyle}"/>
</StackPanel>
如果你需要配置数百个单独的元素,那肯定会很烦人,但我假设你不会有数百种不同的元素类型。
既然如此,你可以为你的类型创建样式,并在那里设置前景色。
理想情况下,这可能在一个ResourceDictionary
中,每个样式都引用一个公共的前景色,比如
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="appForegroundColor" Color="Red" />
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="{StaticResource appForegroundColor}" />
</Style>
<!-- Create styles for Element Types here -->
</ResourceDictionary>
然后,您可以将此资源字典应用于需要它的窗口,例如:
<Window ...>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<TextBlock Text="Foo" />
</Grid>
</Window>
DataTemplate
之类的TextBlocks
无效。 - Amadeusz Wieczorek
Window
上设置Foreground
属性,则该值将通过继承传递给Label
,如下所示:Window(红色)-> Grid(红色[继承])-> ListBox(红色[继承])-> ListBoxItem(红色[继承])-> StackPanel(红色[继承])-> Label(红色[绑定到StackPanel.(TextElement.Foreground)])。 - Pavlo GlazkovSystem.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.FrameworkElement', AncestorLevel='1''. BindingExpression:Path=(0); DataItem=null; target element is 'Border' (Name=''); target property is 'Foreground' (type 'Brush')
- ANeves