底部绘制正确的 WinForms 标签控件






4.83/5 (39投票s)
如何在启用视觉样式时正确绘制底部对齐的 WinForms 标签控件。
引言
当使用 Tab 控件的标签页对齐方式不是“顶部”时,大多数开发人员都会遇到相同的问题:当启用视觉样式时,标签页会错误地绘制(更准确地说,只有顶部方向绘制正确)。一天我也遇到了这个问题。我有一个任务,需要将一个旧的 .NET 1.1 应用程序移植到 .NET Framework 2.0 运行。我想添加视觉样式支持,结果——我们遇到了著名的 Tab 问题。我搜索了网络,找到了一些解决方案,但没有一个让我完全满意。我决定通过继承 System.Windows.Forms.TabControl 来编写自己的控件 UxTabControl
。
您可能会发现我的控件很有用,因为我认为你们中的许多人仍在使用 Windows Forms 而不是 WPF,而且微软甚至在 Windows 8.1 中也没有为 SysTabControl32
添加正确的标签页绘制。那些家伙只要求顶部标签页才能让您的应用程序通过微软认证(顺便说一句,苹果在其界面生成器中从一开始就以任何方向正确实现了他们的标签页;如果您曾经深入使用过 Interface Builder,您就会明白我的意思)。
背景
我以 CodeProject 上 Adi DEDIC 的文章作为起点,您可以阅读那里的“背景”部分。Adi 解释了如何旋转和绘制标签页。我的控件使用了类似的技术。但 Adi 的控件是用 C++ 编写并使用 MFC 的,我的控件主要用托管代码编写,尽管它使用了一些平台互操作。我还从 Mick Doherty 的网站上借鉴了一些关于标签页滚动条的技巧。您也可以在他的实现中找到底部标签页控件,但没有源代码。
Using the Code
使用该控件最简单的方法是将其添加到您的工具箱。为此,只需右键单击工具箱的首选区域,然后在弹出的菜单中选择“选择项...”,在“.NET Framework 组件”选项卡中单击“浏览”,然后查找 UxTabControl.dll。完成!现在,您应该在工具箱中看到 UxTabControl
,您可以像其他控件一样将其拖到您的窗体上。
如果您出于某些原因不想按上述方式使用它(例如,您不使用 Visual Studio,而是使用记事本和命令提示符),则必须将 UxTabControl.dll 添加到您的项目引用库中。之后,在您计划使用该控件的代码中,添加以下指令:
using VSControls;
在 Visual Basic 中
Imports VSControls
在 C++/CLI 中
using namespace VSControls;
现在,您可以像 System.Windows.Forms.TabControl 一样创建和操作 UxTabControl
:
UxTabControl myControl = new UxTabControl();
myControl.Location = new Point(10, 10);
//other code you need
在 Visual Basic 中
Dim myControl As New UxTabControl
myControl.Location = New Point(10, 10)
'other code you need
在 C++/CLI 中
UxTabControl^ myControl = gcnew UxTabControl();
myControl->Location = Point(10, 10)
//other code you need
打开所有项目和解决方案的推荐方法是使用 Visual Studio 2013。它们都以 .NET Framework 4.0 Client Profile(C++/CLI 除外)为目标。如果您碰巧没有 Professional 或更高级版本的 IDE,您可以从 微软网站下载适用于 Windows 桌面的 Express 版本。
要求与限制
- 需要 .NET Framework 4.0 或更高版本才能运行代码。尽管如此,在进行某些修改后,我认为有可能使用旧版本的框架(但不能早于 2.0)来编译代码。
- 自定义绘制不保证在除微软的视觉样式之外的其他视觉样式下都能正常工作。
- 支持的 Windows 系统:Vista、7、8、8.1 及其服务器版本。当然,必须启用视觉样式;否则,绘制将由默认的 Windows 引擎完成(我的设计方式就是这样)。
- 不支持左右标签页对齐。我猜用户需要将头歪向肩膀才能读取标签页的标题,不是很方便,您觉得呢?但是,如果您非常需要这个功能,您可以自己实现。
关注点
- 本文展示了如何通过继承一些标准的 .NET 控件并重写某些属性来实现所需的效果。
- 您将学习如何使用 System.Windows.Forms.VisualStyles 命名空间来绘制某些控件(在本例中是 Tab 控件)的各个部分。
- 此外,代码还展示了如何重写 WndProc 来响应某些 Windows 消息。
历史
- 2009 年 3 月 20 日 - 版本 1.0
- 初始版本
- 2010 年 3 月 7 日 - 版本 1.0.1
- 修复了标签页文本的错误(感谢 SierraMike 的报告)。现在文本是通过 GDI 而不是 GDI+ 绘制的(我找到了“内存位图 + TextRenderer + ClearType 启用”问题的解决方案),因此它能正确地显示在标签页内。
- 2013 年 2 月 22 日 - 版本 1.0.2
- 该控件现在具有一种“透明”背景,即它在绘制自身之前会在其表面上绘制其父项的背景。
- RightToLeft 和 RightToLeftLayout 属性不再禁用。由于绘制问题,它们在以前的版本中被禁用了。
- 该控件已重命名为
UxTabControl
(取自 uxtheme.dll)。之前的名称与特定版本的 Windows 相关,这不太准确。 - 已删除对 Windows XP 和 2003 的支持。我认为这些操作系统已经过时。
- 2014 年 2 月 2 日 - 版本 1.0.3
- 有些人不喜欢 C# 项目中使用的非安全代码。好吧,在 System.Runtime.InteropServices.GCHangle 这个神奇结构体的帮助下,它已经被替换了。这是您从本文下载的所有项目中统一使用的方法。
- 已添加 C++/CLI 项目以完成整个集合。