That is not as easy as it seems. What you essentially want to do is add controls and functionality to an existing control. In order o add the buttons to the tab strip, you have to create a custom control template, because that defines the appearance and visual states of a control. To add functionality to these buttons you would either have to create custom attached properties or create a custom control.
Personally I think that the cleaner way is to create a custom control for this scenario. To make it flexible, we create an area in the tab strip for additional content of any kind and even allow for defining a data template for it.
To start off, create a class that derives from TabControl
and add dependendency properties for the content to be displayed and the optional data template for arbitary content.
public class MyTabControl : TabControl
{
static MyTabControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyTabControl), new
FrameworkPropertyMetadata(typeof(MyTabControl)));
}
public static readonly DependencyProperty AdditionalTabStripContentTemplateProperty = DependencyProperty.Register(
nameof(AdditionalTabStripContentTemplate), typeof(DataTemplate), typeof(MyTabControl), new PropertyMetadata(null));
public static readonly DependencyProperty AdditionalTabStripContentProperty = DependencyProperty.Register(
nameof(AdditionalTabStripContent), typeof(object), typeof(MyTabControl), new PropertyMetadata(null));
public DataTemplate AdditionalTabStripContentTemplate
{
get => (DataTemplate)GetValue(AdditionalTabStripContentTemplateProperty);
set => SetValue(AdditionalTabStripContentTemplateProperty, value);
}
public object AdditionalTabStripContent
{
get => GetValue(AdditionalTabStripContentProperty);
set => SetValue(AdditionalTabStripContentProperty, value);
}
}
Create a style for the new tab control with the additional tab strip content by copying and adapting the default style of the TabControl
, which can be extracted using Blend or Visual Studio.
<SolidColorBrush x:Key="TabItem.Selected.Background" Color="#FFFFFF"/>
<SolidColorBrush x:Key="TabItem.Selected.Border" Color="#ACACAC"/>
<Style x:Key="MyTabControlStyle" TargetType="{x:Type local:MyTabControl}">
<Setter Property="Padding" Value="2"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Background" Value="{StaticResource TabItem.Selected.Background}"/>
<Setter Property="BorderBrush" Value="{StaticResource TabItem.Selected.Border}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyTabControl}">
<Grid x:Name="templateRoot" ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="ColumnDefinition0"/>
<ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition x:Name="RowDefinition0" Height="Auto"/>
<RowDefinition x:Name="RowDefinition1" Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<TabPanel x:Name="headerPanel" Background="Transparent" IsItemsHost="true" Margin="2,2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"/>
<ContentControl Content="{TemplateBinding AdditionalTabStripContent}" ContentTemplate="{TemplateBinding AdditionalTabStripContentTemplate}" Height="{Binding Height, ElementName=headerPanel}" Margin="0, 2, 0, 0"/>
</StackPanel>
<Border x:Name="contentPanel" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabNavigation="Local" KeyboardNavigation.TabIndex="2">
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="TabStripPlacement" Value="Bottom">
<Setter Property="Grid.Row" TargetName="headerPanel" Value="1"/>
<Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="Auto"/>
<Setter Property="Margin" TargetName="headerPanel" Value="2,0,2,2"/>
</Trigger>
<Trigger Property="TabStripPlacement" Value="Left">
<Setter Property="Grid.Row" TargetName="headerPanel" Value="0"/>
<Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="headerPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="contentPanel" Value="1"/>
<Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto"/>
<Setter Property="Width" TargetName="ColumnDefinition1" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
<Setter Property="Margin" TargetName="headerPanel" Value="2,2,0,2"/>
</Trigger>
<Trigger Property="TabStripPlacement" Value="Right">
<Setter Property="Grid.Row" TargetName="headerPanel" Value="0"/>
<Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="headerPanel" Value="1"/>
<Setter Property="Grid.Column" TargetName="contentPanel" Value="0"/>
<Setter Property="Width" TargetName="ColumnDefinition0" Value="*"/>
<Setter Property="Width" TargetName="ColumnDefinition1" Value="Auto"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
<Setter Property="Margin" TargetName="headerPanel" Value="0,2,2,2"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This style is almost the same as the default style. The difference is in the lines below. We use a StackPanel
to add a ContentControl
to the right of the tab headers panel and bind its content and template to the properties of our custom control. We also bind the Height
of the content control to the tab headers panel, so it looks clean.
<StackPanel Orientation="Horizontal">
<TabPanel x:Name="headerPanel" Background="Transparent" IsItemsHost="true" Margin="2,2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"/>
<ContentControl Content="{TemplateBinding AdditionalTabStripContent}" ContentTemplate="{TemplateBinding AdditionalTabStripContentTemplate}" Height="{Binding Height, ElementName=headerPanel}" Margin="0, 2, 0, 0"/>
</StackPanel>
To conclude the style, create an implicit style, so it is applied automatically to all MyTabControl
s in scope.
<Style TargetType="{x:Type local:MyTabControl}" BasedOn="{StaticResource MyTabControlStyle}"/>
Now replace the TabControl
in your XAML with this one and add the tab strip content e.g.:
<local:MyTabControl Grid.Row="1" Grid.ColumnSpan="2">
<local:MyTabControl.AdditionalTabStripContent>
<StackPanel Orientation="Horizontal">
<Button Content="Razveljavi"/>
<Button Content="Ponovi"/>
</StackPanel>
</local:MyTabControl.AdditionalTabStripContent>
<!-- ...your other tab items. -->
</local:MyTabControl>
The cool thing about this is that you can add any content here and even data template it. The result:

The only downside of this template is that tab header collapsing into multiple rows is not possible. If you replace the StackPanel
from above with this DockPanel
, you get a more responsive version, but it will have the buttons on the right border aligned permanently.
<DockPanel LastChildFill="True">
<ContentControl DockPanel.Dock="Right" Content="{TemplateBinding AdditionalTabStripContent}" ContentTemplate="{TemplateBinding AdditionalTabStripContentTemplate}" Height="{Binding Height, ElementName=headerPanel}" Margin="0, 2, 0, 0"/>
<TabPanel DockPanel.Dock="Left" x:Name="headerPanel" Background="Transparent" IsItemsHost="true" Margin="2,2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"/>
</DockPanel>
The result in a normal sized window and a small window that forces a tab header collapse:

