_NT
_NT

Reputation:

WPF styling tabitem text foreground upon trigger such as IsEnabled, IsMouseOver, etc

I'm trying to change the foreground text colour of a WPF tab item's header textblock using triggers. This works fine for most (simpler) scenarios but not when TextBlocks have been globally styled.

So this simple "mouse over" trigger would work in terms of changing the foreground color:

<Style x:Key="testTabItemStyle1" TargetType="{x:Type TabItem}">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Background" Value="White"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
   <Setter.Value>
     <ControlTemplate TargetType="{x:Type TabItem}">
       <Grid SnapsToDevicePixels="true">
         <Border x:Name="Bd" Background="White" BorderBrush="Gray" BorderThickness="1,1,1,0">
            <ContentPresenter HorizontalAlignment="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" x:Name="Content" VerticalAlignment="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" ContentSource="Header"/>
         </Border>
       </Grid>
       <ControlTemplate.Triggers>
         <Trigger Property="IsMouseOver" Value="true">
           <Setter Property="Background" TargetName="Bd" Value="Black"/>
           <Setter Property="Foreground" Value="False"/>
         </Trigger>
       </ControlTemplate.Triggers>
     </ControlTemplate>
   </Setter.Value>
</Setter>
</Style>

The problem is that when TextBlocks are globally styled in App.xaml (for maintaining a consistent look), the foreground does not change, but retains the globally styled foreground color. This is how my TextBlocks are styled:

    <Style TargetType="{x:Type TextBlock}">
        <Setter Property="FontFamily" Value="Arial"/>
        <Setter Property="Foreground" Value="Brown"/>
        <Setter Property="Margin" Value="4,0,4,0"/>
        <Setter Property="TextTrimming" Value="CharacterEllipsis"/>
        <Setter Property="TextWrapping" Value="NoWrap"/>
        <Setter Property="VerticalAlignment" Value="Center"/>
    </Style>

So my question is shouldn't the explicitly defined style assignment (in TabItem's trigger) have precedence? More importantly, how do I work around this without assigning styles to all my textblocks individually but having the TabItem textblock change color as expected?

Many thanks

NT

Upvotes: 0

Views: 12146

Answers (4)

Kent Boogaart
Kent Boogaart

Reputation: 178780

Works for me. Just had to change this:

<Setter Property="Foreground" Value="False"/>

to this:

<Setter Property="Foreground" Value="White"/>

Upvotes: 1

_NT
_NT

Reputation:

Many thanks for your help, you successfully steered me to the right direction.

My intention was to alter the TabItem's text (Created by WPF's ContentPresenter) as opposed to the TextBlock within the tab which is declared in XAML and can easily change colour.

The problem was with the global style taking precedence. And as the TextBlock is created by WPF rather than declared by me, I could not access it.

The solution was to specify the ContentPresenter Resources, as such:

<ControlTemplate TargetType="{x:Type TabItem}">
 <Grid SnapsToDevicePixels="true">
  <Border x:Name="Bd" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1,1,1,0" Padding="{TemplateBinding Padding}">
   <ContentPresenter HorizontalAlignment="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" x:Name="Content" VerticalAlignment="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" ContentSource="Header" RecognizesAccessKey="True">
   <ContentPresenter.Resources>
    <Style TargetType="{x:Type TextBlock}">
         <Setter Property="Foreground" Value="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type TabItem}}}"/>
    </Style>
   </ContentPresenter.Resources>
  </ContentPresenter>
  </Border>
 </Grid>

As you can see I have set the TextBlock style within the ContentPresenter resources. So obviously now any TextBlocks within the ContentPresenter shall use the parent's Foreground property and this will take precedence due to value coercion, solving my problem.

Many thanks to all,

NT

Upvotes: 0

Kenan E. K.
Kenan E. K.

Reputation: 14111

What I meant was this:

<TabItem Header="Summary" x:Name="TabSummary" IsSelected="True" Style="{DynamicResource testTabItemStyle1}">
     <Border x:Name="TabSummaryBody" Margin="-5,-5,-5,-5">
             <StackPanel Margin="0,30,0,0" HorizontalAlignment="Center">
                   <TextBlock Text="Please select a document using the tree view on your right to show its properties." 
                              FontSize="16"
                              Foreground="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}, AncestorLevel=1}, Path=Foreground}"/>
             </StackPanel>
     </Border>
</TabItem>

Binding finds the parent TabItem and binds to its Foreground property.

Upvotes: 0

Kenan E. K.
Kenan E. K.

Reputation: 14111

You are setting the foreground color of a TabItem to Red, not the TextBlock. Maybe the TextBox style is not inherited from TabItem because user set implicit styles have precedence over trigger setters.

Try adding a binding to the TextBlock's parent TabItem Foreground property.

EDIT

Like this

Foreground="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}, AncestorLevel=1}, Path=Foreground}"

Upvotes: 0

Related Questions