0

I want to bind the Background Property of a TabItem programmatically to a custom Property. So far the custom background is only applied when the TabItem is not selected:

Selected Tab

Unselected Tab

The TabItem is programmatically generated together with the Bindings:

Binding binding = new Binding();
binding.Source = this;
binding.Converter = this;
binding.Path = new PropertyPath("HasChanged");
binding.Mode = BindingMode.OneWay;
binding.TargetNullValue = tabItem.Background;
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
BindingOperations.SetBinding(tabItem, TabItem.BackgroundProperty, binding);

I implemented the Interface IValueConverter

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    GradientStopCollection gradient = new GradientStopCollection();
    gradient.Add(new GradientStop(Color.FromRgb(255, 234, 199), 0));
    gradient.Add(new GradientStop(Color.FromRgb(255, 233, 194), 0.5));
    gradient.Add(new GradientStop(Color.FromRgb(255, 225, 173), 0.5));
    gradient.Add(new GradientStop(Color.FromRgb(255, 221, 163), 1));
    Brush brush = new LinearGradientBrush(gradient, 90);
    return (bool)value ? brush : null;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
    return null;
}

How do i have to bind the Property to affect a TabItem that is selected?

  • You need to edit template of `TabItem`. Default template has trigger for `IsSelected` property and inside that trigger they set `Background` to fixed value overwriting your binding. So you need to recreate this template without unnecessary trigger. – Evk Apr 06 '17 at 09:18
  • Please refer to the following answer for an example of how to change the background colour of the selected TabItem: http://stackoverflow.com/questions/42026529/how-can-i-change-the-style-of-a-wpf-tabcontrols-itemtemplate-so-that-i-can-set/42027077#42027077 – mm8 Apr 06 '17 at 09:39

2 Answers2

1

As is stated in the link provided by mm8 in the comment to the question, you'll need to override ControlTemplate of the TabItem. Below is the implementation of TabControl with tabs on the left and custom ControlTemplate of the TabItem. Selected items are highlighted by changing the border's thickness:

<TabControl TabStripPlacement="Left"  
                VerticalAlignment="Stretch"
                HorizontalContentAlignment="Stretch"
                Name="tc"
                ItemsSource="{Binding MySource, Mode=OneWay}"
                ContentTemplate="{StaticResource templateForTheContent}"
                ItemTemplate="{StaticResource templateForTheHeader}">
        <TabControl.Resources>
            <Style TargetType="TabItem">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="TabItem">
                            <Border Name="brdPanel"
                                    CornerRadius="3,0,0,3"
                                    BorderBrush="Black"
                                    Background="{TemplateBinding Background}"
                                    Margin="2,2,0,2"
                                    BorderThickness="1,1,0,1">
                                <ContentPresenter VerticalAlignment="Center"
                                                  HorizontalAlignment="Center"
                                                  ContentSource="Header"
                                                  Margin="10,2" />
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsSelected"
                                         Value="True">
                                    <Setter TargetName="brdPanel"
                                            Property="BorderThickness"
                                            Value="2,2,0,2" />
                                    <Setter TargetName="brdPanel"
                                            Property="Margin"
                                            Value="1,1,0,1" />
                                </Trigger>
                                <Trigger Property="IsSelected"
                                         Value="False">
                                    <Setter TargetName="brdPanel"
                                            Property="BorderThickness"
                                            Value="1,1,0,1" />
                                    <Setter TargetName="brdPanel"
                                            Property="Margin"
                                            Value="2,2,0,2" />
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </TabControl.Resources>
    </TabControl>

Below the binding for Background is manually set to LightCoral (here binding source is set differently than OP's for teh purpose of demonstration):

       MyItemVM myItem=this.tc.Items[0];
       TabItem tabItem = (TabItem)this.tc.ItemContainerGenerator.ContainerFromItem(myItem);

        Binding binding = new Binding();
        binding.Source = myItem;
        binding.Path = new PropertyPath("GroupBackground");
        binding.Mode = BindingMode.OneWay;
        binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        BindingOperations.SetBinding(tabItem, TabItem.BackgroundProperty, binding);

        myItem.GroupBackground = Brushes.LightCoral;

        MyItemVM myItem=this.tc.Items[1];
        tabItem = (TabItem)this.tc.ItemContainerGenerator.ContainerFromItem(myItem);

        binding = new Binding();
        binding.Source = myItem;
        binding.Path = new PropertyPath("GroupBackground");
        binding.Mode = BindingMode.OneWay;
        binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        BindingOperations.SetBinding(tabItem, TabItem.BackgroundProperty, binding);

       myItem.GroupBackground = Brushes.LightCoral;

The result looks like this: enter image description here

Beware this only changes the Background of the Header of TabItem.

Arie
  • 5,251
  • 2
  • 33
  • 54
0

I ended up using parts of Arie's Answer, but I couldn't use his template because I wanted the default Windows Tab style.

My first step was to remove all procedurally generated bindings and converters. Then I used the Tag Property of a TabItem as boolean to mark which tabs should be highlighted.

tabItem.Tag = true;

As Arie said, I needed to overwrite the Template of TabItem in my XAML file. I used this method to generate the default Template of TabItem.

The last step was to define some Setters in Triggers to check if the Tag Property was set to true. In addition you need to define that Tag should be cast to a boolean value instead of a string. For that you need to define sys in your Window element:

<Window ...
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
... >

Interpret Property Tag as boolean:

<Trigger.Value>
    <sys:Boolean>True</sys:Boolean>
</Trigger.Value>

Resulting TabItem template:

<TabControl ... >
    <TabControl.Resources>
        <Style TargetType="TabItem">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="TabItem">
                        <Grid SnapsToDevicePixels="True">
                            <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1,1,1,0" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}">
                                <ContentPresenter x:Name="Content" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" ContentStringFormat="{TemplateBinding HeaderStringFormat}" ContentSource="Header" HorizontalAlignment="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ItemsControl}}}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{Binding VerticalContentAlignment, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ItemsControl}}}"/>
                            </Border>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Background" TargetName="Bd">
                                    <Setter.Value>
                                        <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                                            <GradientStop Color="#FFEAF6FD" Offset="0.15"/>
                                            <GradientStop Color="#FFD9F0FC" Offset="0.5"/>
                                            <GradientStop Color="#FFBEE6FD" Offset="0.5"/>
                                            <GradientStop Color="#FFA7D9F5" Offset="1"/>
                                        </LinearGradientBrush>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                            <Trigger Property="Tag">
                                <Trigger.Value>
                                    <sys:Boolean>True</sys:Boolean>
                                </Trigger.Value>
                                <Setter Property="Background" TargetName="Bd">
                                    <Setter.Value>
                                        <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                                            <GradientStop Color="#FFFFEAC7" Offset="0.15"/>
                                            <GradientStop Color="#FFFFE9C2" Offset="0.5"/>
                                            <GradientStop Color="#FFFFE1AD" Offset="0.5"/>
                                            <GradientStop Color="#FFFFDDA3" Offset="1"/>
                                        </LinearGradientBrush>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                            <Trigger Property="IsSelected" Value="True">
                                <Setter Property="Panel.ZIndex" Value="1"/>
                                <Setter Property="Background" TargetName="Bd" Value="#FFF9F9F9"/>
                            </Trigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="IsSelected" Value="True"/>
                                    <Condition Property="Tag">
                                        <Condition.Value>
                                            <sys:Boolean>True</sys:Boolean>
                                        </Condition.Value>
                                    </Condition>
                                </MultiTrigger.Conditions>
                                <Setter Property="Background" TargetName="Bd" Value="#FFFFE5C1"/>
                            </MultiTrigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="IsSelected" Value="False"/>
                                    <Condition Property="IsMouseOver" Value="True"/>
                                </MultiTrigger.Conditions>
                                <Setter Property="BorderBrush" TargetName="Bd" Value="#FF3C7FB1"/>
                            </MultiTrigger>
                            <Trigger Property="TabStripPlacement" Value="Bottom">
                                <Setter Property="BorderThickness" TargetName="Bd" Value="1,0,1,1"/>
                            </Trigger>
                            <Trigger Property="TabStripPlacement" Value="Left">
                                <Setter Property="BorderThickness" TargetName="Bd" Value="1,1,0,1"/>
                            </Trigger>
                            <Trigger Property="TabStripPlacement" Value="Right">
                                <Setter Property="BorderThickness" TargetName="Bd" Value="0,1,1,1"/>
                            </Trigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="IsSelected" Value="True"/>
                                    <Condition Property="TabStripPlacement" Value="Top"/>
                                </MultiTrigger.Conditions>
                                <Setter Property="Margin" Value="-2,-2,-2,-1"/>
                                <Setter Property="Margin" TargetName="Content" Value="0,0,0,1"/>
                            </MultiTrigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="IsSelected" Value="True"/>
                                    <Condition Property="TabStripPlacement" Value="Bottom"/>
                                </MultiTrigger.Conditions>
                                <Setter Property="Margin" Value="-2,-1,-2,-2"/>
                                <Setter Property="Margin" TargetName="Content" Value="0,1,0,0"/>
                            </MultiTrigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="IsSelected" Value="True"/>
                                    <Condition Property="TabStripPlacement" Value="Left"/>
                                </MultiTrigger.Conditions>
                                <Setter Property="Margin" Value="-2,-2,-1,-2"/>
                                <Setter Property="Margin" TargetName="Content" Value="0,0,1,0"/>
                            </MultiTrigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="IsSelected" Value="True"/>
                                    <Condition Property="TabStripPlacement" Value="Right"/>
                                </MultiTrigger.Conditions>
                                <Setter Property="Margin" Value="-1,-2,-2,-2"/>
                                <Setter Property="Margin" TargetName="Content" Value="1,0,0,0"/>
                            </MultiTrigger>
                            <Trigger Property="IsEnabled" Value="False">
                                <Setter Property="Background" TargetName="Bd" Value="#FFF4F4F4"/>
                                <Setter Property="BorderBrush" TargetName="Bd" Value="#FFC9C7BA"/>
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </TabControl.Resources>
    <TabItem></TabItem>
</TabControl>
Community
  • 1
  • 1