Closable Tab Control In WPF

Introduction

In this article, we will see how we can achieve the Closable Tab Item in Tab Control in WPF.

Crating WPF Application Project

Fire up Visual Studio 2008 and create a WPF Application and name the project as SampleTabControl.

 
WPF Application Project

First, we need to create a Resource Dictionary where we would make our custom control.

Resource Dictionary

Now, before designing the custom control, write the below CS file which is the class that would inherit TabItem.

custom control

Write the following code into the cs file as follows,

Code

Our resource dictionary needs to be changed based on our style. The following XAML represents it.
  1. <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:CloseableTabItemDemo">  
  2.     <Style x:Key="TabItemFocusVisual">  
  3.         <Setter Property="Control.Template"><Setter.Value><ControlTemplate><Rectangle SnapsToDevicePixels="true"Stroke="Black"StrokeDashArray="1 2"StrokeThickness="1"Margin="3,3,3,1"/></ControlTemplate></Setter.Value></Setter>  
  4.     </Style>  
  5.     <SolidColorBrush x:Key="TabControlNormalBorderBrush" Color="#8C8E94" />  
  6.     <LinearGradientBrush x:Key="TabItemHotBackground" EndPoint="0,1" StartPoint="0,0">  
  7.         <GradientStop Color="#EAF6FD" Offset="0.15" />  
  8.         <GradientStop Color="#D9F0FC" Offset=".5" />  
  9.         <GradientStop Color="#BEE6FD" Offset=".5" />  
  10.         <GradientStop Color="#A7D9F5" Offset="1" />  
  11.     </LinearGradientBrush>  
  12.     <SolidColorBrush x:Key="TabItemSelectedBackground" Color="#F9F9F9" />  
  13.     <SolidColorBrush x:Key="TabItemHotBorderBrush" Color="#3C7FB1" />  
  14.     <SolidColorBrush x:Key="TabItemDisabledBackground" Color="#F4F4F4" />  
  15.     <SolidColorBrush x:Key="TabItemDisabledBorderBrush" Color="#FFC9C7BA" />  
  16.     <Style TargetType="{x:Type local:CloseableTabItem}">  
  17.         <Style.Resources><LinearGradientBrush x:Key="ButtonNormalBackground"EndPoint="0,1"StartPoint="0,0"><GradientStop Color="#F3F3F3"Offset="0"/><GradientStop Color="#EBEBEB"Offset="0.5"/><GradientStop Color="#DDDDDD"Offset="0.5"/><GradientStop Color="#CDCDCD"Offset="1"/></LinearGradientBrush><LinearGradientBrush x:Key="ButtonOverBackground"EndPoint="0,1"StartPoint="0,0"><GradientStop Color="#FFFAFAFA"Offset="0"/><GradientStop Color="#FFE0E0E3"Offset="1"/></LinearGradientBrush><LinearGradientBrush x:Key="ButtonPressedBackground"EndPoint="0,1"StartPoint="0,0"><GradientStop Color="#FFE0E0E2"Offset="0"/><GradientStop Color="#FFF8F8F8"Offset="1"/></LinearGradientBrush><SolidColorBrush x:Key="ButtonNormalBorder"Color="#FF969696"/><Style x:Key="CloseableTabItemButtonStyle"TargetType="{x:Type Button}"><Setter Property="FocusVisualStyle"Value="{x:Null}"/><Setter Property="Background"Value="{StaticResource ButtonNormalBackground}"/><Setter Property="BorderBrush"Value="{StaticResource ButtonNormalBorder}"/><Setter Property="BorderThickness"Value="1"/><Setter Property="Foreground"Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/><Setter Property="HorizontalContentAlignment"Value="Center"/><Setter Property="VerticalContentAlignment"Value="Center"/><Setter Property="Padding"Value="4"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type Button}"><Grid><Border SnapsToDevicePixels="true"x:Name="Chrome"Background="{TemplateBinding Background}"BorderBrush="{TemplateBinding BorderBrush}"BorderThickness="{TemplateBinding BorderThickness}"CornerRadius="2"Opacity="0"/><ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"Margin="{TemplateBinding Padding}"VerticalAlignment="{TemplateBinding VerticalContentAlignment}"RecognizesAccessKey="True"/></Grid><ControlTemplate.Triggers><Trigger Property="IsMouseOver"Value="True"><Setter Property="Opacity"TargetName="Chrome"Value="1"/><Setter Property="Background"TargetName="Chrome"Value="{DynamicResource ButtonOverBackground}"/></Trigger><Trigger Property="IsPressed"Value="True"><Setter Property="Opacity"TargetName="Chrome"Value="1"/><Setter Property="Background"TargetName="Chrome"Value="{DynamicResource ButtonPressedBackground}"/></Trigger><Trigger Property="IsEnabled"Value="false"><Setter Property="Foreground"Value="#ADADAD"/></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter>  
  18.     </Style>  
  19.     </Style.Resources>  
  20.     <Setter Property="FocusVisualStyle" Value="{StaticResource TabItemFocusVisual}" />  
  21.     <Setter Property="Foreground" Value="Black" />  
  22.     <Setter Property="Padding" Value="6,1,6,1" />  
  23.     <Setter Property="BorderBrush" Value="{StaticResource TabControlNormalBorderBrush}" />  
  24.     <Setter Property="Background" Value="{StaticResource ButtonNormalBackground}" />  
  25.     <Setter Property="HorizontalContentAlignment" Value="Stretch" />  
  26.     <Setter Property="VerticalContentAlignment" Value="Stretch" />  
  27.     <Setter Property="Template">  
  28.         <Setter.Value>  
  29.             <ControlTemplate TargetType="{x:Type local:CloseableTabItem}">  
  30.                 <Grid SnapsToDevicePixels="true">  
  31.                     <Border x:Name="Bd" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1,1,1,0">  
  32.                         <DockPanel x:Name="ContentPanel">  
  33.                             <Button x:Name="PART_Close" HorizontalAlignment="Center" Margin="3,0,3,0" VerticalAlignment="Center" Width="16" Height="16" DockPanel.Dock="Right" Style="{DynamicResource CloseableTabItemButtonStyle}" ToolTip="Close Tab">  
  34.                                 <Path x:Name="Path" Stretch="Fill" StrokeThickness="0.5" Stroke="#FF333333" Fill="#FF969696" Data="F1 M 2.28484e-007,1.33331L 1.33333,0L 4.00001,2.66669L 6.66667,6.10352e-005L 8,1.33331L 5.33334,4L 8,6.66669L 6.66667,8L 4,5.33331L 1.33333,8L 1.086e-007,6.66669L 2.66667,4L 2.28484e-007,1.33331 Z " HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />  
  35.                             </Button>  
  36.                             <ContentPresenter x:Name="Content" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" ContentSource="Header" RecognizesAccessKey="True" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="{TemplateBinding Padding}" />  
  37.                         </DockPanel>  
  38.                     </Border>  
  39.                 </Grid>  
  40.                 <ControlTemplate.Triggers>  
  41.                     <Trigger Property="IsMouseOver" SourceName="PART_Close" Value="True">  
  42.                         <Setter Property="Fill" TargetName="Path" Value="#FFB83C3D" />  
  43.                     </Trigger>  
  44.                     <Trigger Property="IsPressed" SourceName="PART_Close" Value="True">  
  45.                         <Setter Property="Fill" TargetName="Path" Value="#FF9Dclosable-tab-control-in-wpf8" />  
  46.                     </Trigger>  
  47.                     <Trigger Property="IsMouseOver" Value="true">  
  48.                         <Setter Property="Background" TargetName="Bd" Value="{StaticResource TabItemHotBackground}" />  
  49.                     </Trigger>  
  50.                     <Trigger Property="IsSelected" Value="true">  
  51.                         <Setter Property="Panel.ZIndex" Value="1" />  
  52.                         <Setter Property="Background" TargetName="Bd" Value="{StaticResource TabItemSelectedBackground}" />  
  53.                     </Trigger>  
  54.                     <MultiTrigger>  
  55.                         <MultiTrigger.Conditions>  
  56.                             <Condition Property="IsSelected" Value="false" />  
  57.                             <Condition Property="IsMouseOver" Value="true" />  
  58.                         </MultiTrigger.Conditions>  
  59.                         <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource TabItemHotBorderBrush}" />  
  60.                     </MultiTrigger>  
  61.                     <Trigger Property="TabStripPlacement" Value="Bottom">  
  62.                         <Setter Property="BorderThickness" TargetName="Bd" Value="1,0,1,1" />  
  63.                     </Trigger>  
  64.                     <Trigger Property="TabStripPlacement" Value="Left">  
  65.                         <Setter Property="BorderThickness" TargetName="Bd" Value="1,1,0,1" />  
  66.                     </Trigger>  
  67.                     <Trigger Property="TabStripPlacement" Value="Right">  
  68.                         <Setter Property="BorderThickness" TargetName="Bd" Value="0,1,1,1" />  
  69.                     </Trigger>  
  70.                     <MultiTrigger>  
  71.                         <MultiTrigger.Conditions>  
  72.                             <Condition Property="IsSelected" Value="true" />  
  73.                             <Condition Property="TabStripPlacement" Value="Top" />  
  74.                         </MultiTrigger.Conditions>  
  75.                         <Setter Property="Margin" Value="-2,-2,-2,-1" />  
  76.                         <Setter Property="Margin" TargetName="ContentPanel" Value="0,0,0,1" />  
  77.                     </MultiTrigger>  
  78.                     <MultiTrigger>  
  79.                         <MultiTrigger.Conditions>  
  80.                             <Condition Property="IsSelected" Value="true" />  
  81.                             <Condition Property="TabStripPlacement" Value="Bottom" />  
  82.                         </MultiTrigger.Conditions>  
  83.                         <Setter Property="Margin" Value="-2,-1,-2,-2" />  
  84.                         <Setter Property="Margin" TargetName="ContentPanel" Value="0,1,0,0" />  
  85.                     </MultiTrigger>  
  86.                     <MultiTrigger>  
  87.                         <MultiTrigger.Conditions>  
  88.                             <Condition Property="IsSelected" Value="true" />  
  89.                             <Condition Property="TabStripPlacement" Value="Left" />  
  90.                         </MultiTrigger.Conditions>  
  91.                         <Setter Property="Margin" Value="-2,-2,-1,-2" />  
  92.                         <Setter Property="Margin" TargetName="ContentPanel" Value="0,0,1,0" />  
  93.                     </MultiTrigger>  
  94.                     <MultiTrigger>  
  95.                         <MultiTrigger.Conditions>  
  96.                             <Condition Property="IsSelected" Value="true" />  
  97.                             <Condition Property="TabStripPlacement" Value="Right" />  
  98.                         </MultiTrigger.Conditions>  
  99.                         <Setter Property="Margin" Value="-1,-2,-2,-2" />  
  100.                         <Setter Property="Margin" TargetName="ContentPanel" Value="1,0,0,0" />  
  101.                     </MultiTrigger>  
  102.                     <Trigger Property="IsEnabled" Value="false">  
  103.                         <Setter Property="Background" TargetName="Bd" Value="{StaticResource TabItemDisabledBackground}" />  
  104.                         <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource TabItemDisabledBorderBrush}" />  
  105.                         <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />  
  106.                     </Trigger>  
  107.                 </ControlTemplate.Triggers>  
  108.             </ControlTemplate>  
  109.         </Setter.Value>  
  110.     </Setter>  
  111.     </Style>  
  112. </ResourceDictionary> 
Now, we would design our application. The basic need is to have one Add button and a tab control. See the below figure.

Add Button

The following figure is for your XAML reference.

XAML Reference

Now, in the Button Click event, write the below code to add a TabItem at runtime.

Code

For closing the TabItem, add the Handler for it. Follow the below code.

Code

Now, our application is ready to test. Run it.

Result

That's it. We have successfully achieved adding and removing tabs at runtime.

Hope this article helps you.