Click here to Skip to main content
15,867,453 members
Articles / Desktop Programming / WPF
Article

How to add a Close button to a WPF TabItem

Rate me:
Please Sign up or sign in to vote.
4.91/5 (44 votes)
27 May 2010CPOL4 min read 174.1K   7.4K   59   24
This article shows how to add a Close button to a WPF TabItem. This Close button will only show on the selected tab.

Image 1

Introduction

During a recent project, I had a need for a "Close button" on tabs, similar to that in Visual Studio 2010. While trying to find out how to do this, I found several examples on the Internet. Many of these examples used header templates for the TabItem that used nothing but XAML or XAML mixed with some C# code. Other examples had extra features, like making the tab header a different shape, which I did not need. Although I did have a header template that sort of worked the way I wanted it to, it wasn't perfect. And, since I am not that comfortable with XAML anyways (as I come from a WinForms background), I decided to go another route. I know there are probably simpler ways to accomplish this, but the following solution felt simple and straightforward to me, and hopefully someone else finds it useful.

My tab has several requirements:

  1. The Close button should only show on the currently selected tab - not on all tabs.
  2. If a tab is not currently selected, but you move your mouse over the tab, the close button should appear. When the mouse leaves that tab, the button should disappear again.
  3. When the mouse moves over the Close button ("X"), the color of the "X" should turn red and a tooltip that says "Close" should appear. When the mouse leaves the button, the "X" should turn back to black.
  4. When the Close button is clicked, the tab should close (obviously).
  5. The final requirement is that my tab should show the entire title/description – not just a portion of it. So the size of the tab header should be able to grow and shrink to the title.

To accomplish this task, we need to create two items:

  1. A simple UserControl that contains a Label and a Button.
  2. A custom TabItem with a few overridden methods to handle the showing and hiding of the Close button.

Using the Code

The first item we need to create is the UserControl:

  1. Create a new UserControl and call it CloseableHeader.
  2. Add a Label to this control and call it label_TabTitle.
  3. Add a Button to this control and call it button_close.
  4. Set the style of the button to ToolBar.ButtonStyleKey.
  5. Set  the Text (content) of the button to X.

Here is the complete XAML code for this new UserControl:

XML
<UserControl x:Class="CloseableHeader"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      mc:Ignorable="d" 
      d:DesignHeight="23" d:DesignWidth="81" Margin="0">
    <Grid>
      <Button Content="X"  Height="19" HorizontalAlignment="Right" Margin="0,3,4,0" 
          Name="button_close" VerticalAlignment="Top" Width="20" FontFamily="Courier" 
          FontWeight="Bold" Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" 
          FontStretch="Normal" Visibility="Visible" 
          FontSize="14" Padding="0" ToolTip="Close"/>
      <Label Content="TabItem"  Height="23" HorizontalAlignment="Left" 
          Margin="4,1,0,0" Name="label_TabTitle" VerticalAlignment="Top" 
          FontFamily="Courier" FontSize="12" />
    </Grid>
</UserControl>

The second item we need to create is the custom TabItem:

  1. Create a new class called ClosableTab which inherits from TabItem.
  2. C#
    class ClosableTab : TabItem
    {
    }
  3. Create the constructor.
  4. Here we will create a new instance of the new UserControl CloseableHeader that we created above. We will then assign it to the tab header as shown below. This means that when the TabItem is displayed, it will show our new UserControl on the header. This is exactly what we need as it will display a label and our Close button.

    C#
    // Constructor
    public ClosableTab()
    {
        // Create an instance of the usercontrol
        closableTabHeader = new CloseableHeader();
        // Assign the usercontrol to the tab header
        this.Header = closableTabHeader;
    }
  5. Create a property for setting the “title” of a tab. As shown below, we will simply update the Label in the UserControl.
  6. C#
    /// <summary>
    /// Property - Set the Title of the Tab
    /// </summary>
    public string Title
    {
        set
        {
            ((CloseableHeader)this.Header).label_TabTitle.Content = value;
        }
    }
  7. Next, we will do four overrides to control the visibility of the Close button on the tab.
  8. When the tab is selected – show the Close button like so:

    C#
    // Override OnSelected - Show the Close Button
    protected override void OnSelected(RoutedEventArgs e)
    {
        base.OnSelected(e);
        ((CloseableHeader)this.Header).button_close.Visibility = Visibility.Visible;
    }

    When the tab is deselected – hide the Close button like so:

    C#
    // Override OnUnSelected - Hide the Close Button
    protected override void OnUnselected(RoutedEventArgs e)
    {
        base.OnUnselected(e);
        ((CloseableHeader)this.Header).button_close.Visibility = Visibility.Hidden;
    }

    When the mouse is over a tab – show the Close button like so:

    C#
    // Override OnMouseEnter - Show the Close Button
    protected override void OnMouseEnter(MouseEventArgs e)
    {
        base.OnMouseEnter(e);
        ((CloseableHeader)this.Header).button_close.Visibility = Visibility.Visible;
    }

    When the mouse is not over a tab – hide the Close button like so:

    C#
    // Override OnMouseLeave - Hide the Close Button (If it is NOT selected)
    protected override void OnMouseLeave(MouseEventArgs e)
    {
        base.OnMouseLeave(e);
        if (!this.IsSelected)
        {
            ((CloseableHeader)this.Header).button_close.Visibility = Visibility.Hidden;
        }
    }
  9. Next, we need to handle several of our new UserControl’s events. These event handlers will control the color of the “X” on the button, the width of the UserControl (showing the entire title), and the Close button Click event to close the tab.

Add the following code to the constructor that we already created up above:

C#
// Attach to the CloseableHeader events
// (Mouse Enter/Leave, Button Click, and Label resize)
closableTabHeader.button_close.MouseEnter += 
   new MouseEventHandler(button_close_MouseEnter);
closableTabHeader.button_close.MouseLeave += 
   new MouseEventHandler(button_close_MouseLeave);
closableTabHeader.button_close.Click += 
   new RoutedEventHandler(button_close_Click);
closableTabHeader.label_TabTitle.SizeChanged += 
   new SizeChangedEventHandler(label_TabTitle_SizeChanged);

Add the following event handlers:

C#
// Button MouseEnter - When the mouse is over the button - change color to Red
void button_close_MouseEnter(object sender, MouseEventArgs e)
{
    ((CloseableHeader)this.Header).button_close.Foreground = Brushes.Red;
}
// Button MouseLeave - When mouse is no longer over button - change color back to black
void button_close_MouseLeave(object sender, MouseEventArgs e)
{
    ((CloseableHeader)this.Header).button_close.Foreground = Brushes.Black;
}
// Button Close Click - Remove the Tab - (or raise
// an event indicating a "CloseTab" event has occurred)
void button_close_Click(object sender, RoutedEventArgs e)
{
    ((TabControl)this.Parent).Items.Remove(this);
}
// Label SizeChanged - When the Size of the Label changes
// (due to setting the Title) set position of button properly
void label_TabTitle_SizeChanged(object sender, SizeChangedEventArgs e)
{
    ((CloseableHeader)this.Header).button_close.Margin = new Thickness(
       ((CloseableHeader)this.Header).label_TabTitle.ActualWidth + 5, 3, 4, 0);
}

Note: In the Close button Click event, I am simply closing the tab by calling the parent’s (a TabControl) Items.Remove() method. This can obviously be extended to instead raise an event. Then the program could determine elsewhere what needs to happen when the Close button is clicked. For simplicity of the demo, I am simply closing the tab.

You can now use this custom TabItem like this:

C#
ClosableTab theTabItem = new ClosableTab();
theTabItem.Title = "Small title";
tabControl1.Items.Add(theTabItem);
theTabItem.Focus();

Conclusion

In conclusion, we now have Close buttons on our tabs. This was accomplished by creating a simple UserControl and a custom TabItem. This was relatively straightforward, and it is easy to extend.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionthanks Pin
echbel28-Jan-16 22:41
echbel28-Jan-16 22:41 
GeneralThank Dude Pin
James Tudu18-Feb-15 0:15
James Tudu18-Feb-15 0:15 
QuestionThanks a lot Pin
Member 1114693411-Oct-14 23:57
Member 1114693411-Oct-14 23:57 
QuestionGreat Article for people from WinForms Pin
Abhishek Durvasula1-Jun-14 22:09
Abhishek Durvasula1-Jun-14 22:09 
QuestionApplying a style to Label from another style Pin
Member 1053072517-Jan-14 4:00
Member 1053072517-Jan-14 4:00 
GeneralMy vote of 5 Pin
Sampath Kumar G29-Sep-13 2:16
professionalSampath Kumar G29-Sep-13 2:16 
QuestionDoes not work with Xaml 4 + Pin
Pierresa27-Dec-12 22:11
Pierresa27-Dec-12 22:11 
GeneralMy vote of 5 Pin
Jose Pedro de Leon Alvez14-Nov-12 5:22
Jose Pedro de Leon Alvez14-Nov-12 5:22 
GeneralMy vote of 5 Pin
Roland Wiesinger12-Sep-12 4:28
Roland Wiesinger12-Sep-12 4:28 
GeneralMy vote of 5 Pin
Henry Minute1-Sep-12 8:13
Henry Minute1-Sep-12 8:13 
GeneralNice Pin
nimuirc13-Jul-12 7:08
nimuirc13-Jul-12 7:08 
Question"Unable to cast" Error Pin
mnaftalis6-May-12 3:37
mnaftalis6-May-12 3:37 
GeneralMy vote of 1 Pin
Dreamer3625-Mar-12 4:32
Dreamer3625-Mar-12 4:32 
GeneralMy vote of 2 Pin
Guillaume Waser12-Feb-12 2:19
Guillaume Waser12-Feb-12 2:19 
GeneralMy vote of 5 Pin
maq_rohit23-Jun-11 20:45
professionalmaq_rohit23-Jun-11 20:45 
GeneralMy vote of 5 Pin
Shahin Khorshidnia3-May-11 20:32
professionalShahin Khorshidnia3-May-11 20:32 
GeneralMy vote of 4 Pin
luctranquoc10-Apr-11 22:58
luctranquoc10-Apr-11 22:58 
GeneralMy vote of 5 Pin
sarthakganguly26-Mar-11 2:04
sarthakganguly26-Mar-11 2:04 
GeneralMy vote of 5 Pin
Berryl Hesh10-Feb-11 7:46
Berryl Hesh10-Feb-11 7:46 
QuestionHow would I customize a TabControl to use this? Pin
Berryl Hesh10-Feb-11 7:46
Berryl Hesh10-Feb-11 7:46 
GeneralExactly what I was looking for! Pin
Al Forno9-Nov-10 14:42
Al Forno9-Nov-10 14:42 
GeneralI have a similar one, but... Pin
zameb23-Aug-10 4:47
zameb23-Aug-10 4:47 
GeneralI do something similar in my Cinch MVVM framework Pin
Sacha Barber28-May-10 2:34
Sacha Barber28-May-10 2:34 
GeneralNice Pin
Dan Mos27-May-10 11:30
Dan Mos27-May-10 11:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.