跨平台 .NET 开发:使用 Mono、Portable.NET 和 Microsoft .NET - 作者:Mark Easton, Jason King






4.71/5 (8投票s)
2004 年 11 月 3 日
11分钟阅读

152317
来自本书的示例 - 第 5 章。
![]() |
|
生活的调味品
GUI 工具包
“从伯克利(Berkeley)走出了两个伟大的产品:LSD 和 UNIX。我们不认为这是巧合。” - Jeremy S. Anderson
上世纪 70 年代初,那个年代以闪亮的连体衣、极其喇叭的裤子以及“肥胖猫王时期”这样的说法而闻名,图形用户界面(GUI)从一个黑客的便利工具发展成为我们都认识和喜爱的、价值数十亿美元的业务的公众脸面。一个良好的用户界面对应用程序的影响不容小觑,许多项目、职业生涯和财富的成败都可能在一个树状视图的闪烁间决定。
所以,世界上充满了肤浅的唯美主义者,那又怎样呢?取悦他们很有趣,而图形界面的好处在于,它们提供了一个机会,可以将软件开发的内在艺术展现出来。对于那些不认为软件是艺术的人来说,在完成下一个项目时,花点时间提醒自己,你创造了某些原本不存在的东西。如果创造——即使是带有逻辑的创造——不是艺术,那我就是个穿着凉鞋、嚼着胡子的技术宅(包括棕色长袍和糟糕的个人卫生)。
提示 要了解更多关于 GUI 的历史,请访问优秀的网站 http://www.toastytech.com/guis。
撇开这些哲学性的感慨,现在是时候深入了解可用于 .NET 的令人兴奋的 GUI 工具集合,这些工具可以帮助我们区分专业的、跨平台的 GUI 应用程序和令人刺眼的像素汤。
.NET 图形用户界面的拓扑结构
由于本书涉及多种 CLI 实现和操作系统,因此一个好的起点是弄清楚一个理想的托管 GUI 如何工作。之后,我们将审视每种 CLI 实现如何符合理想的实现。
理想的托管窗口系统
对于梦想轻松移植性的跨平台开发者来说,理想的 .NET 渲染系统将完全用托管代码编写。一种明智的方法将包括以下步骤:
- 创建一个基本的渲染系统,用于在屏幕、打印机或文件等设备上显示基本项,如线条和矩形。
- 开发一个更高级的绘图库,通过使用基本的渲染系统来封装更高级的功能。
- 设计一个类层次结构,该结构使用高级渲染库并捕获用户输入,从而生成一个窗口系统。
虽然这种方法没有什么不对,但这引发了一个问题:何时才能脱离托管代码的安全港,进入不安全代码和内存地址的危险世界?如果这种方法被推向极端,渲染系统将依赖于为托管接口(例如 IVideoDriver
)编写的视频驱动程序,并且硬件供应商将发布符合该接口的视频驱动程序,如图 5-1 所示。
当然,如果硬件制造商用托管代码编写部分视频驱动程序,这不仅会是一场性能灾难,而且会严重越界用户代码,并可能不可挽回地破坏内核代码和用户代码之间的关系。
与托管方法相比,从性能的角度来看,如果所有代码都是用紧凑的汇编语言编写的,而没有一丝托管代码,那将是理想的。
在这两种方法之间找到一条微妙的界限,涉及在托管代码和非托管代码之间仔细分离功能,以在性能和可移植性之间达成妥协。由于设备驱动程序与宿主操作系统固有地绑定在一起,并且大多数操作系统提供了一些通用的渲染功能,因此更现实的分离方法是使用托管窗口和绘图系统,非托管渲染系统调用设备驱动程序,如图 5-2 所示。
虽然在顶尖性能和易于移植的代码之间取得平衡是一回事,但图 5-2 所示的托管方法的主要缺点是,它不可避免地会导致一个标准化接口,该接口在所有平台上看起来都一样,但这与每个平台的原生外观和感觉相悖。
因为有些人喜欢他们的应用程序在所有平台上看起来都一样,而另一些人则喜欢他们的应用程序与操作系统的原生感觉融为一体,坦率地说,跨平台 GUI 开发者是无法取胜的。
基本的 .NET 窗口系统
在考虑了实现跨平台窗口系统的理想方法之后,有必要将我们置于 .NET 窗口系统的现实中,并快速、概念性地看一下不同 CLI 实现所走的路线。
由于 Microsoft .NET 提供了用于绘图的 System.Drawing.dll 程序集和用于窗口的 System.Windows.Forms.dll 程序集,因此其他 CLI 实现也选择了实现这些程序集也就不足为奇了。有趣的是,我们可以看到每种 CLI 实现都采用了截然不同的方法来实现这一目标。
Microsoft .NET Framework
当前的 .NET Framework 通过平台调用(P/Invoke)调用 Win32 API 来实现低级渲染和高级控件。
尽管有人可能会倾向于谴责微软重用和延长旧技术的使用寿命,但由于该公司的这种方法有助于 .NET 的早期发布,并且完美地融入了 Windows 用户界面,因此公平地说,微软的实现展示了高超的技术运用。虽然 Windows Longhorn 看起来将打破微软对旧版 Win32 API 的依赖,但在此期间,.NET Framework 依赖于图 5-3 所示的设计。
由于 Microsoft .NET 仅适用于 Windows,因此其使用 Windows 原生功能并不奇怪,因为它提供了良好的性能,而对可移植性的关注很少。
但是,尽管微软的实现不可移植是可以接受的,因为 System.Windows.Forms
封装的是 Windows GUI 而不是通用的窗口系统,所以一个常见的抱怨是,它实际上应该被称为 Microsoft.Windows.Forms
,而 System
命名空间内的任何内容都应该是平台无关的。
Mono
Mono 提供 GUI 功能的方法已经发展了很长时间,并且随着多种渲染后端和多种部署平台,GUI 的世界一直是一条棘手的路线。究竟会发展成什么样子还有待观察。
对于 System.Drawing
的实现,Mono 在 Windows 上使用 GDI+,在运行 X Windows 的平台上使用 Cairo。如图 5-4 所示,虽然在 Windows 上使用平台调用直接调用 Gdiplus.dll,但在非 Windows 平台上,使用一个模仿 GDI+ 的库。该库又将所有调用传递给 Cairo 库。
注意 Cairo 提供了现代化的矢量图形功能和特性,包括抗锯齿文本渲染和数学变换。其理念是在所有媒体上提供统一的输出,尽管目前只存在 X Windows 和内存图像缓冲区实现。Cairo 计划增加对可移植文档格式(PDF)和 PostScript 输出的支持,这可能优雅地导向跨平台打印支持。有关更多详细信息,请参见 http://www.cairographics.org。
虽然 Mono 的 System.Drawing
实现相对简单,但在 GUI 工具包方面情况并非如此。虽然我们在本章后面会讨论一些替代的 GUI 工具包,但目前有三个 GUI 实现与 Mono 直接相关:使用 Winelib 实现的 System.Windows.Forms
;使用 Gtk# 实现的 System.Windows.Forms
;以及 Gtk#,一个 GTK+ 的托管代码包装器,可以用作 System.Windows.Forms
的替代品。图 5-5 展示了这些策略的应用。
让你的烦恼沉溺:Wine
虽然通常似乎一瓶酒可以解决你跨平台开发的所有烦恼,但 Wine 项目也提供了一些帮助。
Wine 是一个用于 Windows 程序的适应层,它提供了一个环境,允许 Windows 程序在不同的操作系统上加载并以不同程度的成功运行。Wine 包含以下两个独立的部分:
- wine 程序,它加载 Windows 二进制文件并将调用代理到 Windows API 函数。
- Winelib 库,它实现了 Win32 API 库中不断增加的函数子集。
虽然 wine 程序仅在 x86 硬件上运行,并且只能用于运行本机 Windows 应用程序,但 Winelib 库可以用作其 Windows 对应项的替代品,并且可以通过平台调用从 .NET 应用程序访问。
有关 Wine 项目的更多信息,请访问 http://www.winehq.com。
提示 由于 Mono 的两个
System.Windows.Forms
实现目前仍处于开发阶段,因此它们不如 Gtk# 可靠,因此我们的建议是尽可能使用 Gtk#。
由于 Gtk# 在开源社区中拥有强大的追随者,因此在 Gtk# 和 System.Windows.Forms
之间选择是一个政治和实际的双重困境,而事实是这两个命名空间最终都将在各种平台上工作,这使得情况更加复杂。正如你所料,Gtk# 命名空间不能直接与 System.Windows.Forms
互换。这意味着要有效地使用 Gtk#,你需要了解它的所有类型和特性,尽管如果 System.Windows.Forms
不能满足你的需求,这只是一个小小的代价。
从图 5-6 中可以看出,Gtk# 命名空间需要一些支持程序集。每个 Gtk# 程序集不仅直接调用相应的 GTK+ 共享库,而且每个 Gtk# 程序集还调用一个 C 共享库,该库充当 粘合代码 并公开 GTK+ 库未提供的一些高级功能。
Portable.NET
与 Microsoft .NET 和 Mono 不同,Portable.NET 的图形架构倾向于图 5-2 中提倡的线性设计,其中 System.Windows.Forms
构建在 System.Drawing
提供的渲染功能之上。这导致所有控件都用托管代码编写。
为了提供一个可移植的渲染系统,System.Drawing
使用一个辅助命名空间 System.Drawing.Toolkit
,该命名空间定义了可以在包装任意渲染引擎时使用的许多接口。到目前为止,Portable.NET 已经创建了 Win32 的包装器(提供 Windows 可移植性)和 X Windows 的包装器(提供 GNU/Linux、Mac OS X 和其他类 Unix 操作系统的可移植性)。这种架构如图 5-7 所示。
这种架构可能被认为是纯粹主义者的选择,因为它致力于容纳一个良好、可移植的设计。随着其他渲染系统的加入,System.Drawing
和 System.Windows.Forms
命名空间的核心将保持整洁,Portable.NET 社区已经开始讨论包装 Mac OS X Cocoa API,以在 Mac OS X 上获得更原生的 Mac 外观。
提示 对于那些关心编写控件或对小部件的工作原理感兴趣的人来说,Portable.NET 的
System.Windows.Forms
实现的源代码是一个宝贵的资源,尽管您选择将其作为自己控件的基础,但通常的许可规则仍然适用。
替代 GUI 工具包
在检查了 Mono、Portable.NET 和 Microsoft .NET 中包含的标准图形系统之后,现在是时候研究一系列替代的 GUI 工具包了,每个工具包都提供自己的功能和挑战,同时为跨平台开发者的生活增添色彩。虽然来自严格的 Windows 背景的开发者可能会倾向于回避这些工具包并坚持使用 System.Windows.Forms
,但您有许多充分的理由拥抱这些替代的 GUI 工具包。其中一些工具包不仅易于跨不同平台移植,而且还提供不同的功能集,其中一些工具包可以在部署的任何平台上提供原生的外观和感觉。还值得注意的是,当微软在 2006 年发布 Windows Longhorn 时,它将标志着新 Windows GUI 系统 Avalon 的到来,并将无疑取代 System.Windows.Forms
成为开发 Windows GUI 的首选工具。
注意 Avalon 承诺提供最新的基于矢量图形的 GUI,并使用自己的 XML 语言 XAML,有望成为 Windows 上 GUI 开发的未来。幸运的是,一个开源的矢量图形库 VG.NET 已经可用于 .NET。虽然 VG.NET 与 Avalon 不完全相同,但它提供了许多类似的功能,例如导出到 MyXaml(一个开源的 XAML 实现),并且与 Avalon 不同,它现在就可以使用。VG.NET 的下载和更多信息可在 http://www.vgdotnet.org 上获得,MyXaml 的详细信息可在 http://www.myxaml.com 上找到。投资
System.Windows.Forms
的一个优势是,尽管它的日子不多了,但由于 Mono 和 PNET 都在实现自己的版本,System.Windows.Forms
可能会在可预见的未来成为最受欢迎的 .NET GUI 工具包。