将单个 .NET* 应用扩展到两个平台中
日益复杂的开发人员工具以及各种移动技术逐渐、长期、缓慢的融合,为程序员带来了令人眼花缭乱的众多平台选择。然而在面对台式机和 PDA 进行选择时,为何只选一个?您可以同时选择两者。
鉴于“移植”是从一个平台到另一个平台的大规模重写,当前的工具支持您在多个平台中“扩展”您的代码。通过充分利用单个代码库,您即可使您的市场和收入增加一倍或两倍。
但是如何做呢?问题就在于此。
为了演示扩展代码的概念,我们在此以拼图游戏“Slide Puzzle”为例,讲述如何使其在台式机和掌上电脑 PDA 上都能运行。借助 Visual Studio .NET* 2003,您将了解到我们如何创建单个 Visual Basic .NET* 代码库,然后将其融入两个不同的结构。
本入门指南旨在向您介绍在同时针对多个平台进行编码时需要谨记的一些设计考虑事项。只需预先稍事规划,您即可轻松完成棘手的工作。之后,当您希望扩展到 Smartphone* 或甚至 ASP.NET* Web 应用时,您即可运用相同的技术。
尽管其中大多数代码均可用于 Visual Studio 的早期版本,但本入门指南中假定您采用的是 Visual Studio .NET 2003。集成开发环境(IDE)中包括一个 Pocket PC 2002 模拟器。
准备工作
在启动该 IDE 之前,我总是会抽出一些时间来拟定一个特性列表。在针对多个平台编写代码时,此项工作变得更加重要。正如我之前的一篇文章《在多个设备中扩展 JAVA* 应用》所述,您需要制定几项重要决策。
1. 您的平台是否联网?
如果您的目标平台能够接入互联网,那么可以考虑充分利用 Web 服务和/或 ASP.NET 移动控件。在您使用最新或频繁更新的数据时,这一点尤为重要。针对本入门指南,我会创建一些独立应用。
2. 所有平台应具备哪些核心特性?
勿庸置疑,您的应用将拥有一系列确定的核心特性,并且您应当能够在所有目标平台上部署这些特性。而我们当前的例子即是这个拼图,包括拼板,以及启动、破解或退出游戏选项。由于移动设备的显示区域千差万别,因而我选择采用一个简单的拼板尺寸调整机制(puzzle-resizer),以充分利用游戏所提供的所有空间。
3. 各平台最适用的特性都有哪些?
设备越小,花哨的功能就越少。这便意味着削减菜单选项,或甚至删除整个菜单。不过,这在掌上电脑上却是一件有趣的事。一般而言,您为掌上电脑创建的应用同样也能在台式机上运行。扩展到台式机只需添加一些特定的台式机特性。
因而,向您推荐的方法是从核心功能着手并进行纵向扩充。从手持设备开始。接下来,只添加那些充分利用更强大平台的真正必要的组件。这样可以为您的用户提供更多选择,以便其根据需求选择最佳工具。
在 VS.NET 中,尽管您可以针对 .NET Framework* 或 .NET Compact Framework*(.NET CF)进行构建,然而却不能在同一解决方案中同时针对二者进行构建。因此鉴于.NET CF 实质上是 .NET Framework 的一个子集,我将从掌上电脑版本开始构建。因为我知道,若能在这个版本上成功构建,我便能够在任何设备上构建。
文件-> 新建 ->项目。
在“项目类型”下,选择“Visual Basic 项目”;
在“模板”下,选择“智能设备应用”;
我们将其称为“SlidePuzzler”
在“智能设备应用向导”中,选中“掌上电脑”(Windows* 应用)。
绘制窗体
在涉及到代码之前,您需要执行大量的窗体设计工作。
在“Solution Explorer”中,右击“Form1.vb”并选择“属性”;将该文件名改为“SlidePuzzle.vb”。
同样,单击窗体并将窗体名改为“SlidePuzzle”,文本名改为“Slide Puzzle”。
同时,还要记住(我经常会忘记)右击“项目”并选择“属性”,将“启动目标”改为新的窗体名。
在窗体下方,您会看到一个“主菜单 1”对象。选择该对象,并将其名称(在“属性”下)改为“PuzzleMenu”。
在窗体底部(可能需要向下滚动),您会看到菜单文本。您可以通过代码创建上述所有内容,但在此只构建菜单会更加简单。为了简化此项工作,可创建一个菜单选项:“菜单”,其中包含三个子选项:“新游戏”、“破解”和“退出”。
(通过“属性”)为菜单各选项命名:分别为“主菜单”、“新游戏菜单”、“破解菜单”和“退出菜单”。
在窗体上覆盖一个平面,称为“PuzzleBox”。尺寸大小无关紧要,因为它们会通过代码重新调节,但须尽量覆盖整个窗体。
以下是您可以采用的两个图片。“Testgrid.gif”是一个 4×4 网格,带有 50×50 像素大小的拼版(Tile),总尺寸为 200×200 像素。如果您希望通过删除调节大小部分和添加常量来限制拼图的尺寸,那么此图片十分便利。“Gaia.jpg”可为您带来更多优势,且尺寸略大于 PDA 模拟器。将其中一项或将二者全部保存到您的项目目录中,然后将“Gaia.jpg”添加到项目中。
在“Gaia.jpg”图片的“属性”项下,将“构建动作”改为“嵌入式资源”。这样便使其与可执行文件合而为一,而非作为独立的文件。
Testgrid.gif
Gaia.jpg
现在,窗体和项目均已作好准备。我们可以开始编码了。
在扩展应用时,为了充分利用大多数代码,请尽量将操作代码从 UI 分流到其它类型。最理想的情况是,表格代码只包含针对您不同平台的独特代码。正如您所知,此类完美的优化本身便是一门艺术。随着时间的推移,您无疑会发现描绘功能的全新方法,以最充分地利用可扩展代码。
作为您最基本的组件,拼板(Tile)类型首当其冲。它当然代表了您在整个拼图上四处滑动的小方块。启动时,通过右击该项目并选择“添加->添加类型”来为您的项目添加类型。将该类型命名为“Tile.vb”。
由于拼版将用作“PuzzleBox”面板下的窗体控件,因而只需在类型说明下方添加以下代码:
Inherits System.Windows.Forms.Control
接下来是各种成员声明。
Private m_PuzzlePicture As Image
Private m_DisplayRect As Rectangle
Public CurrentLoc As Integer
Sub New 包含的几点无需关注。首先,添加以下代码:
Public Sub New(ByVal m_Image As Image, ByVal m_X As Integer, _
ByVal m_Y As Integer, ByVal m_Width As Integer, _
ByVal m_Height As Integer, ByVal m_Name As Integer)
m_PuzzlePicture = m_Image
m_DisplayRect = New Rectangle(m_X, m_Y, m_Width, m_Height)
Location = New Point(m_X, m_Y)
Size = New Size(m_Width, m_Height)
Text = m_Name
CurrentLoc = m_Name
End Sub
作为窗体控件,拼板(Tile)对象具有除您定义的属性之外的几种额外属性,如位置、大小和文本。这些属性在您围绕拼图平面四处移动拼板(Tile)时迟早会派上用场,特别是位置和大小属性。还需注意的是,在接下来的代码中,CurrentLoc 始终代表拼板(Tile)的当前位置和文本,而对象属性则代表拼板(Tile)的原始位置。对象属性用于支持后来的价值,以进一步提高在应用其它地方对其进行参考的灵活性。
这同样也可作为 .NET CF 与 .NET Framework 之间存在差异的一个例子。在台式机应用中,名称是可以编程方式设定的属性之一。而在 PDA 应用中,名称则为只读而不能设定。为此,在这里将代之以使用文本。这是对从小做起并进行纵向扩充的另一个合理解释。
将图像分割为可移动的小块的关键在于忽略该对象的绘制规则。利用它来绘制整个图像中与这一具体拼板(Tile)相关的特定部分。
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
MyBase.OnPaint(e)
e.Graphics.DrawImage(m_PuzzlePicture, ClientRectangle, _
m_DisplayRect, GraphicsUnit.Pixel)
End Sub
为了简化说明,尚未添加代码以实际扩展或调整拼图的大小。以上代码仅仅展示了更多的可用图像。如果您希望获得更有趣的体验,您还可以为拼板(Tile)创建添加一些算法来调整图像的大小。(实际上,带有 VS.NET 的代码样本包括一个通过 C#* 为掌上电脑编写的 Slide Puzzle 游戏。其中包括除我在此展示的特性之外的几项其它特性,以及一些用于创建拼图游戏的不同技术,但它自身并未轻易参与多平台开发。)
大多数实际工作均在 Grid 类中进行,使用该类表示拼图。其实质上是拼板(Tile)对象以及基本游戏机制所需的所有方法的集合。为项目添加一个新类型,并称之为“Grid.vb”。