`

WPF - Setting foreground color of Entire window

阅读更多

You might as well as I would suppose that if we just set the foreground of a window to something different from its original color, then the whole controls from the window might change as well?
well this is not true, consider this example. 

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

 

 

the reason as pointed by Pavlo Glazkov is as such ...

Pavlo Glazkov 写道
This is because such controls as Label and CheckBox override the Foreground property in their styles.

 

Below is an example a typical logical tree of elements that shows how the value specified on the Window level travels down the tree:

 

Window (Red [Local]) 
  -> Grid (Red [Inherited]) 
     -> ListBox (Red [Inherited]) 
        -> ListBoxItem (Red [Inherited]) 
           -> StackPanel (Red [Inherited]) 
              -> Label (Black [Style])
                 -> TextBlock (Black [Inherited])
              -> TextBlock (Red [Inherited])

 

In square brackets the source of the value is shown.

As you can see the inheritance breaks on theLabelitself because it has theForegroundproperty set in its default style:

 

 

 

<Style x:Key="{x:Type Label}"
       TargetType="{x:Type Label}">
    <Setter Property="Foreground"
            Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    ...
</Style>

 

 

 

As a workaround for this we can use the following trick. Define the default style for such controls (as Label) in the application (in App.xaml or in the Window inself). And in that default style override the Foreground property to set a relative source binding to the nearest ancestor of the control that still has the desired value:

 

 

<StyleTargetType="{x:Type Label}"><SetterProperty="Foreground"Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}, Path=(TextElement.Foreground)}"/></Style><StyleTargetType="{x:Type CheckBox}"><SetterProperty="Foreground"Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}, Path=(TextElement.Foreground)}"/></Style>

 

After that our tree will look like this:

 

 

 

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

 

 

As you can see, our binding restores the inheritance.

Such styles need to be defined for each element that overrides the Foregroundproperty in its style. As @Duane suggested, to not duplicate the binding in each style the BasedOn capability can be used:

 

 

 

<Style x:Key="ForegroundInheritanceFixStyle"TargetType="Control"><SetterProperty="Foreground"Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}, Path=(TextElement.Foreground)}"/></Style><StyleTargetType="{x:Type Label}"BasedOn="{StaticResource ForegroundInheritanceFixStyle}"></Style><StyleTargetType="{x:Type CheckBox}"BasedOn="{StaticResource ForegroundInheritanceFixStyle}"></Style>

 

 

And because of this inheritance relationship, I found there is a problem when I tried to change the default settings for some data control, the change is not affected, it was because the container element is no modified for its fore/ground, background color.  

so, e.g.

 

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:dx="clr-namespace:DevExpress.Xpf.Core;assembly=DevExpress.Xpf.Core.v12.1"
    xmlns:vm="clr-namespace:RiskLayoutExample.ViewModels"
    xmlns:dxg="clr-namespace:DevExpress.Xpf.Grid;assembly=DevExpress.Xpf.Grid.v12.1"
    xmlns:dxdo="http://schemas.devexpress.com/winfx/2008/xaml/docking"
    >
  <DataTemplate DataType="{x:Type vm:RiskDataViewModel}">
    <dx:BackgroundPanel>
      <DataGrid
          HorizontalAlignment="Stretch"
          VerticalAlignment="Stretch"
          ItemsSource="{Binding RiskData}"
                  >
        <DataGrid.Resources>
                      <Style TargetType="TextBlock"  x:Key="{x:Type TextBlock}" >
                      </Style>
                      <Style TargetType="TextBoxBase" x:Key="{x:Type TextBoxBase}" 
                             >
                      </Style>
                      <Style TargetType="TextBox"  x:Key="{x:Type TextBox}" />
                      <Style TargetType="DataGridCell" x:Key="{x:Type DataGridCell}">
                      </Style>
                      <!-- .. -->
        </DataGrid.Resources>

        <DataGrid.Columns>
          <DataGridTextColumn
              Header="Book"
              Binding="{Binding Book}"
              IsReadOnly="True"
                          >
          </DataGridTextColumn>
          <!-- ... -->
        </DataGrid.Columns>
      </DataGrid>
    </dx:BackgroundPanel>
  </DataTemplate>
</ResourceDictionary>

 

 

the text color of the DataGridCell does not change, so I hvae to change the foreground and background of the dxd:BackgroundPanel

So I have to supply the color of the containing element. 

    <dx:BackgroundPanel
      Foreground="White"
      Background="Black">
   </dx:BackgroundPanel>

 

 

References:

Setting Foreground Color of Entire Window

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics