Setting TabItem foreground color also sets the TabControl foreground color

Adrian picture Adrian · Jun 21, 2010 · Viewed 12k times · Source

I have a TabControl that I have restyled. The TabItem has a trigger that is fired when the TabItem is selected that changes the TabItem text to bold and green. The problem I have is that the text in the contents of the tab is also set to bold and green.

I can work around this by setting all of my controls in the tab content to be the color and font weight I want, but should I have to do this? So, I have to make sure that every textblock in the contents area has a style that sets the color to black and font weight normal.

How can I set the IsSelected part of the TabItem to show green, but leave the contents of the tab alone?

I've tried to set the foreground of the TabControl to black, but this doesn't work.

You will see from the code sample below that the text on the first tab is green, and I want it to be black, but without setting each control in the tab content.

Code Sample below:

    <Grid>
    <Grid.Resources>
        <!-- Tab item -->
        <Style TargetType="{x:Type TabItem}">
            <Setter Property="FontSize" Value="14"/>
            <Setter Property="MinWidth" Value="200"/>
            <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TabItem}">
                        <Grid>
                            <Border Name="Border" Padding="5,2">
                                <ContentPresenter ContentSource="Header"/>
                            </Border>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="Border.IsMouseOver" Value="True"/>
                                    <Condition Property="IsSelected" Value="False"/>
                                </MultiTrigger.Conditions>
                                <Setter Property="FontWeight" Value="Bold"/>
                                <Setter Property="Foreground" Value="Black"/>
                            </MultiTrigger>

                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="Border.IsMouseOver" Value="False"/>
                                    <Condition Property="IsSelected" Value="False"/>
                                </MultiTrigger.Conditions>
                                <Setter Property="Foreground" Value="Black" />
                            </MultiTrigger>

                            <Trigger Property="IsSelected" Value="True">
                                <Setter Property="Foreground" Value="Green"/>
                                <Setter Property="FontWeight" Value="Bold"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <!-- Tab control -->
        <Style  TargetType="{x:Type TabControl}">
            <Setter Property="SelectedIndex" Value="0"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TabControl}">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="200" />
                                <ColumnDefinition Width="*" />
                            </Grid.ColumnDefinitions>
                            <Border Grid.Column="0" Padding="5" Margin="0,0,5,0" CornerRadius="3">
                                <StackPanel Orientation="Vertical">
                                    <ScrollViewer VerticalScrollBarVisibility="Auto" FocusVisualStyle="{x:Null}">
                                        <TabPanel IsItemsHost="True"/>
                                    </ScrollViewer>
                                </StackPanel>
                            </Border>
                            <Border Grid.Column="1" BorderBrush="Black" BorderThickness="0">
                                <ScrollViewer VerticalScrollBarVisibility="Auto" FocusVisualStyle="{x:Null}" Padding="10,0">
                                    <ContentPresenter ContentSource="SelectedContent"/>
                                </ScrollViewer>
                            </Border>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    </Grid.Resources>

    <TabControl Name="tabControl" TabStripPlacement="Left">
        <!-- First tab item -->
        <TabItem IsSelected="True">
            <TabItem.Header>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Profile"/>
                </StackPanel>
            </TabItem.Header>
            <TextBlock Text="Page 1 Sample Text with no foreground set." FontSize="30"/>
        </TabItem>

        <!-- Second tab item -->
        <TabItem IsSelected="True">
            <TabItem.Header>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Profile"/>
                </StackPanel>
            </TabItem.Header>
            <TextBlock Text="Page 2 Sample Text with foreground set manually." FontSize="30" Foreground="Red"/>
        </TabItem>
    </TabControl>
</Grid>

Answer

Gilad picture Gilad · Apr 21, 2011

I have just come across this very same problem, and after fiddling around with it a little I think I have found a more elegant solution.

I'm saying more elegant since it would leave the ContentPresenter intact, and apply the foreground and fontweight setters to the ContentPresenter's TextElement (which is basically an attached property, but that's beside the point).

The main advantage of this approach is that replacing the ContentPresenter with a TextBlock implicitly assumes that the header will only contain text, which limits the usability of the workaround and produces a less robust code. Leaving the ContentPresenter in place will allow any content, e.g. images+text.

One more thing you would have to do is name your ContentPresenter:

<Setter Property="Template">
     <Setter.Value>
         <ControlTemplate TargetType="{x:Type TabItem}">
             <Grid>
                <Border Name="Border" Padding="5,2">
                   <ContentPresenter x:Name="CP" ContentSource="Header"/>
                </Border>
             </Grid>
             <ControlTemplate.Triggers>
                <MultiTrigger>
                   <MultiTrigger.Conditions>
                      <Condition Property="Border.IsMouseOver" Value="True"/>
                      <Condition Property="IsSelected" Value="False"/>
                   </MultiTrigger.Conditions>
                     <Setter Property="TextElement.FontWeight" TargetName="CP" Value="Bold"/>
                     <Setter Property="TextElement.Foreground" TargetName="CP" Value="Black"/>                                
                </MultiTrigger>...

Now the Foreground and FontWeight will not be inherited by the contents of the TabItem (tested).

Enjoy :)