如何在 WPF TabItem 中添加关闭按钮
本文展示了如何在 WPF TabItem 中添加关闭按钮。该关闭按钮仅在选定的选项卡上显示。
引言
在最近的一个项目中,我需要在选项卡上添加一个“关闭按钮”,类似于 Visual Studio 2010 中的那样。在尝试找到如何实现这一点时,我在 Internet 上找到了一些示例。这些示例中的许多都使用标题模板用于 TabItem
,除了 XAML 或 XAML 与一些 C# 代码混合使用外,什么也没有。其他示例具有额外的功能,例如使选项卡标题具有不同的形状,这是我不需要的。虽然我确实有一个标题模板,它以某种方式按照我想要的方式工作,但它并不完美。而且,由于我对 XAML 不是很熟悉(因为我来自 WinForms 背景),我决定走另一条路。我知道可能有更简单的方法来实现这一点,但以下解决方案对我来说感觉简单明了,希望其他人也能觉得它有用。
我的选项卡有几个要求
- 关闭按钮应**仅**在当前选定的选项卡上显示 - **而不是**在所有选项卡上。
- 如果未选中选项卡,但您将鼠标悬停在选项卡上,则应显示关闭按钮。当鼠标离开该选项卡时,该按钮应再次消失。
- 当鼠标移动到关闭按钮(“**X**”)上时,“**X**”的颜色应变为红色,并应显示一个显示“关闭”的工具提示。当鼠标离开按钮时,“**X**”应恢复为黑色。
- 单击关闭按钮时,应关闭选项卡(显而易见)。
- 最后一个要求是我的选项卡应显示**整个**标题/描述 - 而不仅仅是其中的一部分。因此,选项卡标题的大小应该能够增长和缩小以适应标题。
为了完成此任务,我们需要创建两个项目
- 一个简单的 UserControl,其中包含一个
Label
和一个Button
。 - 一个自定义
TabItem
,带有一些重写的方法来处理关闭按钮的显示和隐藏。
Using the Code
我们需要创建的第一个项目是 UserControl
- 创建一个新的 UserControl 并将其命名为
CloseableHeader
。 - 向此控件添加一个
Label
并将其命名为label_TabTitle
。 - 向此控件添加一个
Button
并将其命名为button_close
。 - 将按钮的样式设置为
ToolBar.ButtonStyleKey
。 - 将按钮的
Text
(内容)设置为 X。
这是这个新 UserControl 的完整 XAML 代码
<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>
我们需要创建的第二个项目是自定义 TabItem
- 创建一个名为
ClosableTab
的新类,该类继承自TabItem
。 - 创建构造函数。
- 创建一个用于设置选项卡的“标题”的属性。如下所示,我们将简单地更新 UserControl 中的
Label
。 - 接下来,我们将进行四个重写来控制选项卡上关闭按钮的可见性。
- 接下来,我们需要处理我们新的 UserControl 的几个事件。这些事件处理程序将控制按钮上“**X**”的颜色、UserControl 的宽度(显示整个标题)以及关闭按钮的 Click 事件以关闭选项卡。
class ClosableTab : TabItem
{
}
在这里,我们将创建上面创建的新 UserControl CloseableHeader
的一个新实例。然后,我们将它分配给选项卡标题,如下所示。这意味着当显示 TabItem
时,它将在标题上显示我们的新 UserControl。这正是我们所需要的,因为它将显示一个标签和我们的关闭按钮。
// Constructor
public ClosableTab()
{
// Create an instance of the usercontrol
closableTabHeader = new CloseableHeader();
// Assign the usercontrol to the tab header
this.Header = closableTabHeader;
}
/// <summary>
/// Property - Set the Title of the Tab
/// </summary>
public string Title
{
set
{
((CloseableHeader)this.Header).label_TabTitle.Content = value;
}
}
当选择选项卡时 - 像这样显示关闭按钮
// Override OnSelected - Show the Close Button
protected override void OnSelected(RoutedEventArgs e)
{
base.OnSelected(e);
((CloseableHeader)this.Header).button_close.Visibility = Visibility.Visible;
}
取消选择选项卡时 - 像这样隐藏关闭按钮
// Override OnUnSelected - Hide the Close Button
protected override void OnUnselected(RoutedEventArgs e)
{
base.OnUnselected(e);
((CloseableHeader)this.Header).button_close.Visibility = Visibility.Hidden;
}
当鼠标悬停在选项卡上时 - 像这样显示关闭按钮
// Override OnMouseEnter - Show the Close Button
protected override void OnMouseEnter(MouseEventArgs e)
{
base.OnMouseEnter(e);
((CloseableHeader)this.Header).button_close.Visibility = Visibility.Visible;
}
当鼠标**未**悬停在选项卡上时 - 像这样隐藏关闭按钮
// 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;
}
}
将以下代码添加到我们已经在上面创建的构造函数中
// 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);
添加以下事件处理程序
// 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);
}
注意:在关闭按钮的 Click 事件中,我只是通过调用父级(TabControl
)的 Items.Remove()
方法来关闭选项卡。这显然可以扩展为改为引发一个事件。然后,程序可以在其他地方确定单击关闭按钮时需要发生什么。为了演示的简单起见,我只是关闭选项卡。
您现在可以像这样使用这个自定义 TabItem
ClosableTab theTabItem = new ClosableTab();
theTabItem.Title = "Small title";
tabControl1.Items.Add(theTabItem);
theTabItem.Focus();
结论
总之,我们现在在选项卡上有了关闭按钮。这是通过创建一个简单的 UserControl 和一个自定义 TabItem
来完成的。这相对简单明了,并且易于扩展。