Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How to add a Close button to a WPF TabItem

0.00/5 (No votes)
27 May 2010 1  
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. /// <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:

    // 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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here