Click here to Skip to main content
Click here to Skip to main content

How to add a Close button to a WPF TabItem

, 27 May 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
This article shows how to add a Close button to a WPF TabItem. This Close button will only show on the selected tab.

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:

<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. 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.

    // 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. /// <span class="code-SummaryComment"><summary>
    </span>/// Property - Set the Title of the Tab
    /// <span class="code-SummaryComment"></summary>
    </span>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:

    // 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:

    // 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:

    // 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:

    // 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:

// 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:

// 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:

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)

Share

About the Author

Ed Fink

United States United States
No Biography provided

Comments and Discussions

 
GeneralThank Dude PinmemberJames Tudu18-Feb-15 1:15 
QuestionThanks a lot PinmemberMember 1114693412-Oct-14 0:57 
QuestionGreat Article for people from WinForms PinmemberAbhishek Durvasula1-Jun-14 23:09 
QuestionApplying a style to Label from another style PinmemberMember 1053072517-Jan-14 5:00 
GeneralMy vote of 5 PinprofessionalSampath Kumar G29-Sep-13 3:16 
QuestionDoes not work with Xaml 4 + PinmemberPierresa27-Dec-12 23:11 
GeneralMy vote of 5 PinmemberJose Pedro de Leon Alvez14-Nov-12 6:22 
GeneralMy vote of 5 PinmemberRoland Wiesinger12-Sep-12 5:28 
GeneralMy vote of 5 PinmemberHenry Minute1-Sep-12 9:13 
GeneralNice Pinmembernimuirc13-Jul-12 8:08 
Question"Unable to cast" Error Pinmembermnaftalis6-May-12 4:37 
GeneralMy vote of 1 PinmemberDreamer3625-Mar-12 5:32 
GeneralMy vote of 2 PinmemberGuillaume Waser12-Feb-12 3:19 
GeneralMy vote of 5 Pinmembermaq_rohit23-Jun-11 21:45 
GeneralMy vote of 5 PinmemberShahin Khorshidnia3-May-11 21:32 
GeneralMy vote of 4 Pinmemberluctranquoc10-Apr-11 23:58 
GeneralMy vote of 5 Pinmembersarthakganguly26-Mar-11 3:04 
GeneralMy vote of 5 PinmemberBerryl Hesh10-Feb-11 8:46 
QuestionHow would I customize a TabControl to use this? PinmemberBerryl Hesh10-Feb-11 8:46 
GeneralExactly what I was looking for! PinmemberMark Harmon9-Nov-10 15:42 
GeneralI have a similar one, but... Pinmemberzameb23-Aug-10 5:47 
GeneralI do something similar in my Cinch MVVM framework PinmvpSacha Barber28-May-10 3:34 
GeneralNice PinmemberMDL=>Moshu27-May-10 12:30 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150301.1 | Last Updated 27 May 2010
Article Copyright 2010 by Ed Fink
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid