目录
介绍
背景
使用代码
TabWindow库的细分
带有关闭按钮的自定义TabItem
派生的TabControl支持自定义选项卡之间的拖放
允许将一个窗口切换到另一个窗口的TabWindow
总结
- 下载源代码35 KB
本文介绍了一个称为TabWindow的Shell窗口,它嵌入了TabControl,允许通过拖放将选项卡项分离到一个新窗口。它还允许通过拖放将浮动窗口选项卡固定到窗口中。
背景您能想象WPF窗口的行为类似于Chrome或Internet Explorer浏览器吗?在运行时,可以通过拖放将一个窗口选项卡移动到另一个窗口中。选项卡可以重新排序,单个选项卡可以关闭。TabWindow支持这些功能。但是,它不仅仅是Chrome等现代浏览器的复制品。有一些主要区别。例如,当TabWindow中选项卡仅剩一项时,选项卡页头就会消失。在GUI中,空间是一项额外的功能,如您所知。同样,当您将一个窗口选项卡移动到另一个窗口时,也可以将其拖到标题栏,而不是由Chrome浏览器拖到选项卡标题的位置。TabWindow,但是,不是一个docking控制。已经有许多商业和开源docking控件可用。TabWindow派生自WPF Window 类,因此所有窗口特性都由开发人员公开。
使用代码在您的代码中使用TabWindow很简单。在将对TabWindow库的引用添加到您的项目后,首先将TabWindow实例化为常规WPF窗口的引用,然后通过传递将成为TabWindow实例内容的Control实例来调用AddTabItem方法。因此,构建您自己的漂亮用户控件,然后将其传递给TabWindow。
TabWindow.TabWindow tabWin = new TabWindow.TabWindow();
TextBox tb = new TextBox();
tb.Text = "Test Demo";
tabWin.AddTabItem(tb.Text, tb);
tabWin.Show();
根据您的需要,创建尽可能多的TabWindow,然后通过将一个窗口拖到另一个窗口上来开始选项卡窗口。当一个窗口被拖动进入固定TabWindow对象的边界时,将出现一个选项卡放置目标图像。继续拖动,直到鼠标指针悬停在选项卡放置图像上方,然后放开鼠标。拖动的窗口消失,固定的窗口将添加一个新选项卡,其中包含拖动的窗口的内容。
1、两个独立悬浮的TabWindows。
2、将“Test 0”窗口拖到“Test Demo”窗口上。
3、选项卡区域在“测试演示”窗口中突出显示。释放按下的鼠标按钮,然后将“Test 0”窗口切换到“Test Demo”窗口。
为了将选项卡分离到新窗口,请按住选项卡标题并将其拖出现有窗口,或双击选项卡标题。它将创建一个独立的窗口。
TabWindow库的细分库中主要包括三个部分。每个部分负责其自身的功能。
- 使用关闭按钮的自定义TabItem
- 派生自支持自定义TabItem拖放的TabControl
- 允许将一个窗口切换到另一个窗口的TabWindow
根据Internet上的快速搜索,有多种方法可以完成此任务。我采用了一种方法来创建一个衍生自TabItem的自定义控件。为了在选项卡标题上绘制[x]标记,控件模板样式在XAML中声明。最初,我想到了在选择选项卡时使用图像文件显示[x]标记,但最终使用System.Windows.Shapes.Path对象绘制x形状。这是在Generic.xaml中定义[x]按钮的方式。
...
如下所示,此关闭按钮样式将应用于选项卡标题模板。DockPanel由停靠在最右侧的[X]和标头ContentPresenter组成。[x]按钮的默认可见性被隐藏。选择选项卡后,它变为可见。用于Trigger显示或隐藏[x]按钮。
...
...
现在我们需要进行一些操作。我希望在单击[x]按钮时将选项卡项删除。双击选项卡标题时,我也想引发一个事件。此双击通知将由TabWindow使用,在那里它将生成一个新 TabWindow并将内容从单击的选项卡项移动到新窗口。基本上,这等效于将选项卡拖出到新窗口,因此双击选项卡标题可创建一个新TabWindow实例,并删除双击的选项卡项。
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
Button closeButton = base.GetTemplateChild("tabItemCloseButton") as Button;
if (closeButton != null)
closeButton.Click += new System.Windows.RoutedEventHandler(closeButton_Click);
Grid headerGrid = base.GetTemplateChild("gridHeader") as Grid;
if (headerGrid != null)
headerGrid.MouseLeftButtonDown +=
new MouseButtonEventHandler(headerGrid_MouseLeftButtonDown);
}
void closeButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
var tabCtrl = this.Parent as TabControl;
if (tabCtrl != null)
tabCtrl.Items.Remove(this);
}
void headerGrid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ClickCount == 2)
this.RaiseEvent(new RoutedEventArgs(TabHeaderDoubleClickEvent, this));
}
派生的TabControl支持自定义选项卡之间的拖放
网上有很多拖放教程,因此我将不详细介绍通过拖放对选项卡进行重新排序。但是,将选项卡拖出以创建新窗口不是典型的拖放操作。.NET Framework提供了在拖动鼠标指针期间连续引发的QueryCotinueDrag事件。拖动的鼠标位置保持选中状态,当它离开选项卡控件边界时,它会创建一个新的TabWindow。一旦新的TabWindow被创建,新窗口的Left和Top属性通过处理QueryContinueDrag事件得到更新。当放置操作发生时,此事件还提供信号。由于e.KeyStates被设定为DragDropKeyStates.None,是时候从选项卡控件中删除选项卡项。
void DragSupportTabControl_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
{
if (e.KeyStates == DragDropKeyStates.LeftMouseButton)
{
Win32Helper.Win32Point p = new Win32Helper.Win32Point();
if (Win32Helper.GetCursorPos(ref p))
{
Point _tabPos = this.PointToScreen(new Point(0, 0));
if (!((p.X >= _tabPos.X && p.X = _tabPos.Y && p.Y 0; i--)
{
System.Windows.Controls.TabItem item = items[i - 1] as
System.Windows.Controls.TabItem;
if (item != null)
((ITabWindow)dragWin).RemoveTabItem(item);
}
}
targetWin.OnDrageLeave();
}
if (_dragEnteredWindows.Count > 0 && ((ITabWindow)dragWin).TabItems.Count == 0)
{
((Window)dragWin).Close();
}
_dragEnteredWindows.Clear();
}
总结
TabWindow库在复合应用程序中非常有用,在复合应用程序中,模块可以直接加载到TabWindow实例中。然后,将如何将窗口动态合并到选项卡的决定权留给用户。TabWindow的亮点是:
- 允许对选项卡项进行重新排序
- 允许关闭选项卡项
- 当窗口中仅剩一个选项卡项时,选项卡标题将不可见
- 可以将选项卡项拖出到新窗口
- 双击选项卡标题会创建一个新窗口
- 可以通过标题栏拖动一个窗口并将其放在另一个窗口上。源窗口的内容成为目标窗口的新选项卡项。