Search code examples
wpftabcontrolcontroltemplatewpf-style

Changing Border of WPF Tab Control Dynamically


I'm using my own control template for the TabControl and TabItem in the application resource of my project.

In the template, the selected TabItem is colored depending on a property 'SelectedBrush' which returns a Brush. I would also like the Border of the Tab Control (boTabControl, the border around the content presenter) to do be the same color as the selected TabItem.

Is this a code thing, or can it be done in the application resource?

<Style TargetType="{x:Type TabControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TabControl}">
                <Grid Margin="0">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>
                    <TabPanel Grid.Row="0" Panel.ZIndex="1" Margin="0,3,0,0" IsItemsHost="True" Background="Transparent"/>
                    <Border x:Name="boTabControl" Grid.Row="1" BorderThickness="1,3,0,0" CornerRadius="0" Padding="0" Margin="0" BorderBrush="{DynamicResource SelectedBrush}">
                        <ContentPresenter ContentSource="SelectedContent" Margin="0"/>
                    </Border>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsEnabled" Value="True">
                        <Setter TargetName="boTabControl" Property="BorderBrush" Value="{Binding SelectedBrush}" />
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter TargetName="boTabControl" Property="BorderBrush" Value="Blue" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<Style TargetType="{x:Type TabItem}">
    <Setter Property="IsTabStop" Value="False"/>
    <Setter Property="FontSize" Value="20"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TabItem}">
                <Grid x:Name="Panel" Background="Transparent">
                    <Border x:Name="Border" Margin="0,0,-3,0" BorderThickness="1,1,1,0" CornerRadius="10,30,0,0">
                        <ContentPresenter x:Name="ContentSite" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ContentSource="Header" Margin="10"/>
                    </Border>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter Property="FontWeight" Value="Bold" />
                        <Setter TargetName="Border" Property="Background" Value="{Binding SelectedBrush}" />
                        <Setter Property="Foreground" Value="White" />
                    </Trigger>
                    <Trigger Property="IsSelected" Value="False">
                        <Setter TargetName="Border" Property="Background" Value="LightGray" />
                        <Setter Property="FontWeight" Value="Normal" />
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="FontWeight" Value="Bold" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
Public ReadOnly Property SelectedBrush As Brush
    Get
        If Me.tcMain.SelectedItem Is Nothing Then
            Return Brushes.Aquamarine
            Exit Property
        End If
        Dim myTabItem As TabItem = Me.tcMain.SelectedItem
        Dim myBrush As Brush = Brushes.Blue
        Select Case myTabItem.Name
            Case Me.tiSale.Name
                myBrush = Brushes.Green
            Case Me.tiReturn.Name
                myBrush = Brushes.Red
            Case Me.tiStock.Name
                myBrush = Brushes.Black
            Case Me.tiAdmin.Name
                myBrush = Brushes.Purple
        End Select

        Return myBrush
    End Get
End Property

Solution

  • here is an approach with an attached property SelectedBrush of type Brush

    add Attached class to project (and make build):

    public class Attached
    {
        public static DependencyProperty SelectedBrushProperty = DependencyProperty.RegisterAttached("SelectedBrush", typeof(Brush), typeof(Attached));
    
        public static Brush GetSelectedBrush(DependencyObject obj)
        {
            return (Brush) obj.GetValue(SelectedBrushProperty);
        }
    
        public static void SetSelectedBrush(DependencyObject obj, Brush value)
        {
            obj.SetValue(SelectedBrushProperty, value);
        }
    }
    

    then assign colors to each TabItem:

    <TabControl>
        <TabItem Name="tiSale" local:Attached.SelectedBrush="Green" Header="123"/>
        <TabItem Name="tiReturn" local:Attached.SelectedBrush="Red" Header="abc"/>
        <TabItem Name="tiStock" local:Attached.SelectedBrush="Black" Header="XYZ"/>
    </TabControl>
    

    change TabControl template to use Attached.SelectedBrush:

    <Style TargetType="{x:Type TabControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TabControl}">
                    <Grid Margin="0">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="*"/>
                        </Grid.RowDefinitions>
                        <TabPanel Grid.Row="0" Panel.ZIndex="1" Margin="0,3,0,0" IsItemsHost="True" Background="Transparent"/>
                        <Border x:Name="boTabControl" Grid.Row="1" 
                                BorderThickness="1,3,0,0" 
                                BorderBrush="{Binding Path=SelectedItem.(local:Attached.SelectedBrush), RelativeSource={RelativeSource TemplatedParent}}"
                                CornerRadius="0" Padding="0" Margin="0">
                            <ContentPresenter ContentSource="SelectedContent" Margin="0"/>
                        </Border>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    

    to use the same brush for TabItem, change Background setter like this:

    <Setter TargetName="Border" Property="Background" 
            Value="{Binding (local:Attached.SelectedBrush), RelativeSource={RelativeSource TemplatedParent}}" />
    

    SelectedBrush property from code behind is not used here