设置整个窗口的前景色

时间:2011-03-16 15:46:39

标签: c# wpf

我想将前景(文本)颜色设置为我的所有元素 你认为这很容易,但不是......

<Window Foreground="Red">
   <Label Content="Test"/>
   <Label Content="Test"/>
   <CheckBox Content="Checkbox"/>
</Window>

这没有任何效果......我能让这个工作的唯一方法就是我专门为每个元素设置Foreground属性。如果你有数百个元素等,这会很烦人。

也许你知道一种方式?

4 个答案:

答案 0 :(得分:26)

这是因为LabelCheckBox等控件会覆盖其样式中的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>

作为解决方法,我们可以使用以下技巧。在应用程序中定义此类控件的默认样式(如Label)(在App.xaml中或在Window inself中)。并且在该默认样式中覆盖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>

希望这有帮助。

答案 1 :(得分:6)

遗憾的是,样式在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>

希望这有帮助。

编辑:

您可以使用下面的Pavlo方法来恢复继承,并使其更容易使用,如下所示:

<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代码(BTW,我认为TextBlock默认继承;没有覆盖的默认样式)。

答案 2 :(得分:0)

是的,在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>

答案 3 :(得分:0)

如果您要配置数百个单独的元素,那肯定会很烦人,但我假设您不会有数百个不同的类型元素。

在这种情况下,您可以做的一件事是为您的类型创建样式,并在那里设置前景色。

理想情况下,这可能位于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>