Changing Border of WPF Tab Control Dynamically - wpf

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

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

Related

XAML Listbox Styled as radio button group with Title

I have this style:
<Style x:Key="RadioButtonList" TargetType="{x:Type ListBox}">
<!-- ControlTemplate taken from MSDN http://msdn.microsoft.com/en-us/library/ms754242.aspx -->
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="MinWidth" Value="120"/>
<Setter Property="MinHeight" Value="80"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<Border
Name="Border"
Background="Transparent"
BorderBrush="Transparent"
BorderThickness="0"
CornerRadius="2">
<ScrollViewer
Margin="0"
Focusable="false">
<StackPanel Margin="2" IsItemsHost="True" />
</ScrollViewer>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="Border" Property="Background" Value="Transparent" />
<Setter TargetName="Border" Property="BorderBrush" Value="Transparent" />
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListBoxItem}" >
<Setter Property="Margin" Value="2" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border Name="theBorder" Background="Transparent">
<RadioButton Focusable="False"
IsHitTestVisible="False"
IsChecked="{TemplateBinding IsSelected}">
<ContentPresenter />
</RadioButton>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
Used as this :
<ListBox
Grid.Column="2"
Style="{StaticResource RadioButtonList}"
ItemsSource="{Binding ModosConsultaSaldos}"
DisplayMemberPath="Description"
SelectedItem="{Binding ModoConsultaSaldos,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
Shows something like this:
But now I want to add a Title using the same Style,
Is this posible? How ?
This could be done in a number of ways. The easiest is simply to stick a label in front of the ListBox in the XAML whenever you use it. But if you want to enforce a consistent style, you'll want something better than that.
We could add properties to ListBox by writing a subclass of ListBox that adds a Header property (I'm going to call it Header instead of Title because that's what a built-in WPF control would call it).
But a slightly more flexible option is to write the Header property as an attached property. We'll also throw in a HeaderTemplate attached property as well, so you can style the header content appropriately. This is common WPF practice in controls that have headers, such as MenuItem or GroupBox. Those WPF controls have HeaderTemplateSelector and HeaderStringFormat properties as well; I'll leave those as an exercise for the student.
First, the attached properties: This is all boilerplate except for the names and types.
public static class ListBoxEx
{
public static Object GetHeader(ListBox obj)
{
return (Object)obj.GetValue(HeaderProperty);
}
public static void SetHeader(ListBox obj, Object value)
{
obj.SetValue(HeaderProperty, value);
}
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.RegisterAttached("Header", typeof(Object), typeof(ListBoxEx),
new FrameworkPropertyMetadata(null) { AffectsMeasure = true, AffectsParentMeasure = true });
public static Object GetHeaderTemplate(ListBox obj)
{
return (Object)obj.GetValue(HeaderTemplateProperty);
}
public static void SetHeaderTemplate(ListBox obj, Object value)
{
obj.SetValue(HeaderTemplateProperty, value);
}
public static readonly DependencyProperty HeaderTemplateProperty =
DependencyProperty.RegisterAttached("HeaderTemplate", typeof(Object), typeof(ListBoxEx),
new FrameworkPropertyMetadata(null) { AffectsMeasure = true, AffectsParentMeasure = true });
}
Now we'll add these to the Template:
...
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<Border
Name="Border"
Background="Transparent"
BorderBrush="Transparent"
BorderThickness="0"
CornerRadius="2"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ContentControl
Content="{TemplateBinding local:ListBoxEx.Header}"
ContentTemplate="{TemplateBinding local:ListBoxEx.HeaderTemplate}"
/>
<ScrollViewer
Margin="0"
Focusable="false"
Grid.Row="1"
>
<StackPanel Margin="2" IsItemsHost="True" />
</ScrollViewer>
</Grid>
</Border>
And we'll give your Style another setter, to create a default header template that does the underlining you had in your screenshot:
<Setter Property="local:ListBoxEx.HeaderTemplate">
<Setter.Value>
<DataTemplate>
<Label
Content="{Binding}"
BorderBrush="Black"
BorderThickness="0,0,0,1"
HorizontalAlignment="Left"
/>
</DataTemplate>
</Setter.Value>
</Setter>
And we use it like this:
<ListBox
Style="{StaticResource RadioButtonList}"
ItemsSource="{Binding ModosConsultaSaldos}"
local:ListBoxEx.Header="Saldos"
...
/>

Change image when TabItem is selected

I want to change image when TabItem is selected.
This is my XAML
<TabControl>
<TapItem>
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<Image Source="aa.png"/>
<TextBlock>AA</TextBlock>
</StackPanel>
</TabItem.Header>
</TapItem>
When TabItem selected, I want to change from "aa.png" to "sel_aa.png".
You can add triggers to your TabItem ControlTemplate
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
</Grid.RowDefinitions>
<Border Grid.Row="0" Name="Border">
<ContentPresenter Content="AA" VerticalAlignment="Center" Margin="5" HorizontalAlignment="Center" ContentSource="Header" />
</Border>
<Image Grid.Row="1" x:Name="Image"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="Red" />
<Setter TargetName="Image" Property="Image.Source" Value="sel_aa.png" />
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="Border" Property="Background" Value="Green" />
<Setter TargetName="Image" Property="Image.Source" Value="aa.png" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
When your TabItem is selected a trigger is fired and the image source will change to sel_aa, when TabItem is not selected the image source will be aa.

WPF TabControl MVVM: Overflow Of TabItems

I am currently working on a Plug-In for AutoCAD, scripting language is VB.net.
Basically I have a User Control which holds a TabControl, each TabItem is an object which just holds the TabItem.Header and TabItem.Content definition. The TabItems are generated dynamically through a xml file. As I am using MVVM this is all stored in an ObservableCollection which is bound to the TabControl items.
As I am fighting with MVVM a little bit and I am rather new to WPF I need a little guidance on the following task: Everything is working fine so far but the only problem I have is that I want a little button at the end of the visible TabItems. When I click on it I can switch through all the Tabs, doesn't matter if they are visible or not.
For a better undertstanding, this should be the desired result:
Image File
I just want a simple explanation on how to achieve that (all the samples on the net are rather complex to me). I tried it with a ScrollViewer, but the result is bad. Here is the current code:
TabControl Template:
<Style x:Key="TabControl"
TargetType="{x:Type TabControl}">
<Setter Property="Background"
Value="{StaticResource TabBackground}">
</Setter>
<Setter Property="BorderBrush"
Value="{StaticResource TabItemActiveBorder}">
</Setter>
<Setter Property="BorderThickness"
Value="0,1,1,0">
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<StackPanel>
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Visible">
<TabPanel x:Name="HeaderPanel"
Panel.ZIndex="1"
KeyboardNavigation.TabIndex="1"
Grid.Column="0"
Grid.Row="0"
Margin="2,2,2,0"
IsItemsHost="true" />
</ScrollViewer>
<ContentPresenter x:Name="PART_SelectedContentHost"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
Margin="{TemplateBinding Padding}"
ContentSource="SelectedContent" />
</StackPanel>
<!--<Grid>
<Grid.RowDefinitions KeyboardNavigation.TabNavigation="Local">
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ScrollViewer>
<TabPanel x:Name="HeaderPanel"
Panel.ZIndex="1"
Margin="0,0,4,-1"
IsItemsHost="True"
KeyboardNavigation.TabIndex="1"
Background="Transparent" />
</ScrollViewer>
</Grid>-->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="TabItem"
TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border Name="Border"
Margin="0,-2,5,0"
Padding="0,1,0,1"
Height="55"
BorderBrush="{StaticResource TabItemActiveBorder}"
CornerRadius="0,5,5,0">
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="2,5,2,5"
RecognizesAccessKey="True" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected"
Value="True">
<Setter Property="Panel.ZIndex"
Value="100" />
<Setter TargetName="Border"
Property="Margin"
Value="-1,-2,1,0" />
<Setter Property="TextElement.Foreground"
Value="{StaticResource TabItemActiveText}" />
<Setter TargetName="Border"
Property="Background"
Value="{StaticResource TabBackground}" />
<Setter TargetName="Border"
Property="BorderThickness"
Value="0,1,1,1" />
</Trigger>
<Trigger Property="IsSelected"
Value="false">
<Setter Property="TextElement.Foreground"
Value="{StaticResource TabItemInactiveText}" />
<Setter TargetName="Border"
Property="Background"
Value="{StaticResource TabItemInactiveBackground}" />
<Setter TargetName="Border"
Property="BorderThickness"
Value="0,1,1,1" />
</Trigger>
<Trigger Property="IsEnabled"
Value="False">
<Setter TargetName="Border"
Property="Background"
Value="{StaticResource InActiveControlBackGround}" />
<Setter TargetName="Border"
Property="BorderBrush"
Value="{StaticResource InActiveControlBackGround}" />
<Setter Property="Foreground"
Value="{StaticResource InActiveControlBackGround}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<ContentPresenter Content="{TemplateBinding Content}">
<ContentPresenter.LayoutTransform>
<RotateTransform Angle="270" />
</ContentPresenter.LayoutTransform>
</ContentPresenter>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
mainWindow XAML excerpt:
<Grid Background="{StaticResource TabBackground}">
<Grid Margin="0,96,0,0">
<TabControl ItemContainerStyle="{StaticResource TabItem}"
TabStripPlacement="Right"
ItemsSource="{Binding loadedPalettes}"
Style="{StaticResource TabControl}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}">
<TextBlock.LayoutTransform>
<RotateTransform Angle="270" />
</TextBlock.LayoutTransform>
</TextBlock>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<UserControls:tabDataGrid />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
TabItem Class:
Private Property _Header As String
Public Property Header As String
Get
Return _Header
End Get
Set(value As String)
_Header = value
End Set
End Property
Private Property _Content As String
Public Property Content As String
Get
Return _Content
End Get
Set(value As String)
_Content = value
End Set
End Property
Thanks in advance!
I solved the problem by myself. Here is the working piece of template code:
<Style x:Key="TabControl"
TargetType="{x:Type TabControl}">
<Setter Property="Background"
Value="{StaticResource TabBackground}">
</Setter>
<Setter Property="BorderBrush"
Value="{StaticResource TabItemActiveBorder}">
</Setter>
<Setter Property="BorderThickness"
Value="0,1,1,0">
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ScrollViewer HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
Grid.Column="1"
Grid.Row="0">
<TabPanel x:Name="HeaderPanel"
Panel.ZIndex="1"
Margin="0,2,2,2"
IsItemsHost="True"
Background="Transparent" />
</ScrollViewer>
<ContentPresenter x:Name="PART_SelectedContentHost"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
Margin="{TemplateBinding Padding}"
ContentSource="SelectedContent" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Tab Item and Tab Control Border Style

How do I style the Tab Control Border so that the selected Tab Item does not have a line underneath it?
These are my Tab Control and Tab Item styles so far.
<!-- Tab control styling -->
<Style TargetType="{x:Type TabControl}">
<Setter Property="Padding" Value="10,5,10,5" />
<Setter Property="Margin" Value="3.5" />
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}" />
</Style>
<!-- Tab item styling -->
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border
Name="Border"
Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
BorderBrush="Black"
BorderThickness="1,1,1,0"
CornerRadius="3,3,0,0"
MinWidth="120">
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="12,2,12,2"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="True" >
<Setter Property="Background" TargetName="Border" Value="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}" />
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock FontWeight="Bold" Text="{Binding}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsMouseOver" Value="True" >
<Setter Property="Background" TargetName="Border" Value="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}" />
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock FontWeight="Bold" Text="{Binding}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsSelected" Value="True" >
<Setter Property="Background" TargetName="Border" Value="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}" />
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock FontWeight="Bold" Text="{Binding}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
If I can achieve the look displayed in the screenshot without having to overload the tab item control template then I don't have an issue as the default tab item template doesn't have the line underneath it on the selected tab. I haven't been able to do this so far. Thanks for your help.
The XAML below is how I have overridden the TabControl to solve this problem. The key piece of info is the Margin property of the HeaderPanel. You will see that the bottom margin is -1, which shifts it down just enough to cover up that line.
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid KeyboardNavigation.TabNavigation="Local">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TabPanel x:Name="HeaderPanel"
Grid.Row="0"
Panel.ZIndex="1"
Margin="0,0,4,-1"
IsItemsHost="True"
KeyboardNavigation.TabIndex="1"
Background="Transparent" />
<Border x:Name="Border"
Grid.Row="1"
BorderThickness="1"
KeyboardNavigation.TabNavigation="Local"
KeyboardNavigation.DirectionalNavigation="Contained"
KeyboardNavigation.TabIndex="2">
<Border.Background>
<SolidColorBrush Color="White"/>
</Border.Background>
<Border.BorderBrush>
<SolidColorBrush Color="White"/>
</Border.BorderBrush>
<ContentPresenter x:Name="PART_SelectedContentHost"
Margin="4"
ContentSource="SelectedContent" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Add property Padding="0,0,0,0" to tab control :-)
Instead of modifying tabcontrol template, you may as well just modify the TabItem template, by adding two lines to cover up the border, and using minus margins for covering up.
(Please take a look at "TopLineCover" and "BottomLineCover" borders.)
<Style TargetType="TabItem" BasedOn="{StaticResource {x:Type TabItem}}">
<Setter Property="Foreground" Value="{DynamicResource VsBrush.WindowText}"/>
<Setter Property="Background" Value="{DynamicResource VsBrush.Window}"/>
<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="HeaderBorder" Padding="8,3,8,3" BorderThickness="1,1,1,0"
Background="{DynamicResource {x:Static commonControls:ColorService.JobViewHeaderBrushKey}}"
BorderBrush="{DynamicResource {x:Static commonControls:ColorService.JobViewHeaderBorderBrushKey}}">
<ContentPresenter x:Name="Content" ContentSource="Header"
HorizontalAlignment="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"
VerticalAlignment="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"
/>
</Border>
<Border x:Name="TopLineCover" BorderThickness="1,1,1,0" Margin="0,-2,0,0" Height="3" Panel.ZIndex="100"
Background="{DynamicResource VsBrush.Window}" BorderBrush="{DynamicResource {x:Static commonControls:ColorService.JobViewHeaderBorderBrushKey}}"
VerticalAlignment="Top" HorizontalAlignment="Stretch" Visibility="Collapsed"/>
<Border x:Name="BottomLineCover" BorderThickness="0,0,0,3" Margin="1,0,1,-2" Panel.ZIndex="100" BorderBrush="{DynamicResource VsBrush.Window}"
VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Visibility="Collapsed"/>
</Grid>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
<Condition Property="IsSelected" Value="False"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="HeaderBorder" Value="{DynamicResource VsBrush.Window}"/>
</MultiTrigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" TargetName="HeaderBorder" Value="{DynamicResource VsBrush.Window}"/>
<Setter Property="Visibility" TargetName="TopLineCover" Value="Visible"/>
<Setter Property="Visibility" TargetName="BottomLineCover" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
In the past I've accomplished this by making the TabItem extend a little further down then it's allocated, so its actually drawn on top of the border element and hides it
I can't remember how I did it exactly, but I think it was with a negative margin on the bottom of the TabItem

WPF TabControl Templates + ItemContainerStyle

I am attempting to create a Tab Control Style that basically looks like buttons at the top that are centered and content panel below that displays the tabitem content.
I have am kind of new to templates but what I have so far works very well except one thing. I want to be able to set the default forground color for text elements. Normally I have accomplished this by using the ContentPresenter with dependency elements. So something like this.
<ContentPresenter TextElement.Foreground="White"/>
This basically makes any TextElement Control written by this Presenter to inherit this property.
Now I am trying to do the same thing but it's not working! I believe it has something to do with my style being wrong.
Style:
<Style x:Key="MainMenuTab" TargetType="{x:Type TabControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid KeyboardNavigation.TabNavigation="Local" Width="{TemplateBinding Width}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Tab Headers Panel -->
<Grid Grid.Row="0" Background="{StaticResource Brush_ApplicationTabBackground}">
<TabPanel
Name="HeaderPanel"
Grid.Row="0"
Panel.ZIndex="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
IsItemsHost="True"
KeyboardNavigation.TabIndex="1"
Background="{StaticResource Brush_ApplicationTabBackground}"
>
</TabPanel>
</Grid>
<!-- Tab Body -->
<Border
Name="Border"
Grid.Row="1"
Background="{StaticResource Brush_ApplicationBackground}"
BorderBrush="Transparent"
BorderThickness="1"
CornerRadius="2"
KeyboardNavigation.TabNavigation="Local"
KeyboardNavigation.DirectionalNavigation="Contained"
KeyboardNavigation.TabIndex="2" >
<ContentPresenter
Name="PART_SelectedContentHost"
Margin="4"
ContentSource="SelectedContent" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<!-- Each Tab should look like this -->
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid Background="{StaticResource Brush_ApplicationTabBackground}">
<Border Width="50" x:Name="BorderTab" Height="50" Margin="5" BorderThickness="1" ClipToBounds="True" BorderBrush="Transparent" Background="Transparent" CornerRadius="5">
<Rectangle x:Name="BackgroundRec" Fill="Transparent" Stroke="Transparent" Width="50" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ContentPresenter Name="TheHeaderContentPresenter" Width="50" Height="50" Margin="5" ContentSource="Header" HorizontalAlignment="Center" VerticalAlignment="Center" TextElement.Foreground="White"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.Setters>
<Setter TargetName="BorderTab" Property="BorderBrush" Value="{StaticResource Brush_ApplicationTabHighlight}"/>
<Setter TargetName="BorderTab" Property="BorderThickness" Value="3"/>
<Setter TargetName="BackgroundRec" Property="Fill" Value="{StaticResource Brush_ApplicationTabHighlight}"/>
<Setter Property="Panel.ZIndex" Value="1"/>
</Trigger.Setters>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Trigger.Setters>
<Setter TargetName="BorderTab" Property="BorderBrush" Value="{StaticResource Brush_ApplicationTabBackground}"/>
<Setter TargetName="BorderTab" Property="BorderThickness" Value="0"/>
<Setter TargetName="BackgroundRec" Property="Fill" Value="{StaticResource Brush_ApplicationTabBackground}"/>
</Trigger.Setters>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
In my ContentPresenter under ItemContainerStyle has the TextElement.Foreground="White" property but it will not print white text!
My tabcontrol that uses this style looks like this:
<TabControl Grid.Row="2" Style="{StaticResource MainMenuTab}">
<TabItem>
<TabItem.Header>
<TextBlock VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,0,0,5" Text="{x:Static UIStrings:ClientStrings.MainWindow_TabHeader_SingleWaveLength}"></TextBlock>
</TabItem.Header>
<TextBlock>TEST PANEL</TextBlock>
</TabItem>
</TabControl>
I know this is compicated but I would really love this to work.
Solution Found.
Based on HCL's post, I have found a solution. I am experiance the same exact problem I am trying to have the content presenter set the inherited dependence property. instead I simple tell the template to apply the dependance property, that way each tabitem is styled to have this property and therefore sets it for all it's children.
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="TabItem">
<Setter Property="TextElement.Foreground" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid Background="{StaticResource Brush_ApplicationTabBackground}">
<Border Width="50" x:Name="BorderTab" Height="50" Margin="5" BorderThickness="1" ClipToBounds="True" BorderBrush="Transparent" Background="Transparent" CornerRadius="5">
<Rectangle x:Name="BackgroundRec" Fill="Transparent" Stroke="Transparent" Width="50" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ContentPresenter Name="TheHeaderContentPresenter" Width="50" Height="50" Margin="5" ContentSource="Header" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.Setters>
<Setter TargetName="BorderTab" Property="BorderBrush" Value="{StaticResource Brush_ApplicationTabHighlight}"/>
<Setter TargetName="BorderTab" Property="BorderThickness" Value="3"/>
<Setter TargetName="BackgroundRec" Property="Fill" Value="{StaticResource Brush_ApplicationTabHighlight}"/>
<Setter Property="Panel.ZIndex" Value="1"/>
</Trigger.Setters>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Trigger.Setters>
<Setter TargetName="BorderTab" Property="BorderBrush" Value="{StaticResource Brush_ApplicationTabBackground}"/>
<Setter TargetName="BorderTab" Property="BorderThickness" Value="0"/>
<Setter TargetName="BackgroundRec" Property="Fill" Value="{StaticResource Brush_ApplicationTabBackground}"/>
</Trigger.Setters>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
All I've really dont is added the line:
<Setter Property="TextElement.Foreground" Value="White"/>
Before the control template! Also I took the white text out of the content presenter because it is useless.
Check this post, it looks to me as it is the same effect:
ContentPresenter within ControlTemplate cannot change attached dependency property

Resources