运用Asp.Net Mobile Controls 开发面向移动平台的Web Application
Background
从1996年至2000年,微软相继推出了基于嵌入式平台的操作系统Windows CE1.0、CE1.2、CE2.0、CE2.12等一列版本,但由于硬件平台和自身设计的原因,没有取得市场成功。2000年,微软推出Windows CE3.0,在产品设计与用户界面上都作了相当大的改变,为表示凤凰涅磐般的改变,微软将Windows CE3.0 冠名为Pocket PC2000。Pocket PC2000比之前辈无论性能和易用性上,都有巨大的进步,相比当时如日中天的Palm OS,也要出色,因此获得了市场成功。随后微软推出了Pocket PC2002、Pocket PC2003以及Windows CE4.5,功能进一步加强,硬件环境也进一步加强,为各种应用提供了比较良好的运行平台。与之同时,WAP与DoMoCo的iMode技术也已成熟并得到了广泛应用。PDA和手机等移动终端接入Internet,但是移动设备Web应用开发者面临着这样一个问题:移动设备的类型纷繁芜杂,上面的web 浏览器采用的技术标准与能力,亦不相同,为每一种类型的移动设备开发相同的应用,显然不很妙。为解决这个问题,微软提供了Microsoft Mobile Internet Toolkit(MMIT),随着Visual Studio 2003的发布,微软将MMIT集成到了VS开发环境中,发展成为Mobile Web Control。
Mobile Web Application Architecture
Asp.Net Mobile 提供一系列服务端的技术,扩展了Asp.Net编程模式,使之能够发布内容到各式各样的移动设备上。每类设备的能力集不相同,不像面向桌面的Web应用,面对的都是采用HTML标准的浏览器,为此,Asp.Net Mobile(或MMIT)便扮演了这样一个角色:各种移动设备之上的一个抽象层,开发者只需关注这个抽象层,不必关心每种目标设备的细节。Asp.Net Mobile的工作流程可以用图1.1来表示:
图1.1 Asp.Net Mobile 工作流程
从图1.1我们可以看到,MMIT内容引擎(MMIT Runtime Rendering Engine)是Web Application向Mobile Device发布内容的桥梁。相应的,MMIT内容引擎是怎样的从Web Application获取内容,并根据请求内容的设备特性,将内容以合适的形式发布给设备的呢?图1.2展示了这个过程,我们可以看到,在其中扮演关键角色的是Device Adapter,它根据请求设备的能力,生成不同的目标内容。
图1.2 Asp.Net Mobile 内容引擎工作流程
Programming
1 创建
Microsoft将移动设备的Web开发组件集成到了Visual Studio .Net 2003中,并且与Asp .Net融合,作为Asp .Net的一个子集。在Vs.Net 2003的IDE中,可以很方便的创建基于移动平台的(PDA, SmartPhone …)Web应用:在工程向导中选择Asp.NET Mobile Web Application,创建面向移动平台的Web工程(如图2.1),如同普通的Asp.Net Application,编译环境将会生成一个工程文件(*.csproj),一个Web配置文件web.Conifg,一个全局作用与定义文件Global.asax,以及一个初始页面文件(*.apsx)。我们不妨假设创建了一个名为mwa(mobile web application)的工程,生成名为myPage.aspx页面文件,同时生成名为myPage的类来负责定义和描述叶面在服务端的行为,与Aps.Net不同的是,myPage类派生System.Web.UI.MobileControls.MobilePage,而不是派生自System.Web.UI.Page。实际上,MobilePage是Page的子类,因此可以认为myPage是Page的孙子,两者有很多相同的行为和特征,但不能这么认为:反正myPage是Page的孙子,好的,我对面向对象有经验,Page能做的,myPage也一定能做。两者的异同将在下面的段落中比较。
图2.1 创建Mobile Web Application
2 web.Config 探索
在Asp.Net mobile 工程中,web.Config 文件内有一项关键的配置:deviceFilters,如下:
<deviceFilters>
<filter name="isJPhone" compare="Type" argument="J-Phone" />
<filter name="isHTML32" compare="PreferredRenderingType" argument="html32" />
<filter name="isWML11" compare="PreferredRenderingType" argument="wml11" />
<filter name="isCHTML10" compare="PreferredRenderingType" argument="chtml10" />
<filter name="isGoAmerica" compare="Browser" argument="Go.Web" />
<filter name="isMME" compare="Browser" argument="Microsoft Mobile Explorer" />
<filter name="isMyPalm" compare="Browser" argument="MyPalm" />
<filter name="isPocketIE" compare="Browser" argument="Pocket IE" />
<filter name="isUP3x" compare="Type" argument="Phone.com 3.x Browser" />
<filter name="isUP4x" compare="Type" argument="Phone.com 4.x Browser" />
...
<filter name="supportsCookies" compare="Cookies" argument="true" />
<filter name="supportsJavaScript" compare="Javascript" argument="true" />
<filter name="supportsVoiceCalls" compare="CanInitiateVoiceCall" argument="true" />
</deviceFilters>
deviceFilters配置节点由一系列的过滤项目()组成,我们不妨就称它们为filter,每个filter都表示一个布尔值,这些filter区别了不同的设备以及设备的能力(Capability Combination),譬如,通过将http request中的Browser项与"Pocket IE"比较,则可以确定名称为"isPocketIE"的filter的值,从而得到关于目标设备的信息,Render Engine便根据这一组filter的值委托不同的Render Adapter为目标设备生成内容。
3 编辑页面
在页面编辑打开myPage.aspx页面,如同设计普通的ASPX页面一样,我们可以将Toolbox栏中Mobile Web Forms选项卡中的控件通过拖拽放到Web Form中。所有的Mobile Controls都用mobile前缀标记,例如mobile:Label。这似乎和设计布局Aspx页面时一样,但好景不长,我们很快就会发现:
1. 每一行竟然只能放下一个Mobile Control。
2. 对齐工具(Align Tools)都不能用了。
3. 我用了TABLE来做页面布局框架,让后将Mobile Control放到Table Cell中,在设计环境中,TABLE起了作用,让页面布局整齐美观。可是,当我试图在浏览器中看到运行效果时,看到的却是一个凌乱不堪的页面,仿佛小时候在墙上的涂鸦之作,所有的TABLE标记都消失的无影无踪,精心的设计付之东流,用户当然不会对这样的页面满意。
4. CSS不起作用了,我必须为每个页面元素设定我喜欢的风格。
5. 结论让我沮丧:我在设计布局Aspx页面时的经验和技巧似乎都不合时宜了。
幸运的是,Mobile Web Control提供了解决其中部分问题的方案,就是运用DeviceSpecific Control。DeviceSpecific Control能够根据你所给出的Choice,在运行时表现不同的内容,下面是一个小实例。在支持html3.2标准的设备上(pocket pc系列),我发现Table标记起作用了,但是,所有的标记元素都必须在一些Template容器内,而Form,Panel等这些窗体元素又对应着不尽相同的Template。在设计视图(Design View)中,我们只能Template Control加入到Choice容器中,而不能编辑Template Control中的内容;要编辑Template Control的内容,必须切换的Html视图(Html View),手工写入标记内容。这是不是有些项传统的ASP或CGI开发,代码要一行一行的写。可以这么说,编辑Mobile Page就是在创建和编辑一系列的Template,当然那些呈现内容简单的页面没有必要使用Template。Template是如此的重要,需要我们专门用一节来讨论。
<mobile:DeviceSpecific id="DeviceSpecific1" runat="server">
<Choice Filter="isHTML32">
<HeaderTemplate>
<table border="1" bgColor="blue">
<tr>
<td>This is Cell1</td>
<td>This is Cell2</td>
</tr>
</table>
</HeaderTemplate>
</Choice>
<Choice Filter="">
<HeaderTemplate>
<mobile:Label Text="This is Cell1" Runat="server" />
<mobile:Label Text="This is Cell2" Runat="server" />
</HeaderTemplate>
</Choice>
</mobile:DeviceSpecific>
4. Template
Form, Panel, List, ObjectList 等mobile web Control 均支持应用Template,它们也是最常用的几种容器控件。从表面上看,它们都实现了Itemplateable接口,实质上,Itemplateble接口没有任何成员,只是一个标记而已。对于怎样开发自定义的支持Template的Web Control,可以参见.Net Framework Document中的Implementing Templated Rendering等章节。这里只讨论在Form, Panel, List, ObjectList这四中最常用的容器控件中怎样使用Template Control。表4.1常用容器控件与它们的Template。
Container Control
Template
Remark
Form
Header Template
HeaderTemplate中的内容将在Form标记开始处被呈现<form … ID="Form1"> {header content}
Footer Template
FooterTemplate中的内容将在Form标记结束之前被呈现{footer content}</form>
Panel
ContentTemplate
ContentTemplate中的内容作为Panel的内容被呈现
List
HeaderTemplate
HeaderTemplate中的内容在列表开始处被呈现。分页模式下,在每一页中List的起始处,HeaderTemplate都将被呈现
FooterTemplate
FooterTemplate中的内容在列表结束储备呈现。份页模式下,在每一页中List的结束处,FooterTemplate都将被呈现
ItemTemplate
ItemTemplate中的内容将被作为List中的每一项被呈现
AlternatingItemTemplate
如果定义了AlternatingItemTemplate,ItemTemplate和AlternatingItemTemplate中的内容将被作为List中的每一项被交叉呈现
SeparatorTemplate
SeparatorTemplate中的内容作为连续项之间的间隔被呈现
HeaderTemplate
与List相同
FooterTemplate
与List相同
ItemTemplate
与List相同
AlternatingItemTemplate
与List相同
SeparatorTemplate
与List相同
ItemDetailsTemplate
ObjectList用来表示复杂对象,在ItemDetailsTemplate中,可以定制对象详细信息的
表4.1 常用容器控件与Template
灵活恰当的应用Template,才能够设计出美观实用的面向移动设备的web 页面。下面,我将用一个完整的示例展示Template的应用。这个示例向我们描述了应用objectList展现邮件列表的方法。
<%@ Register TagPrefix="mobile" Namespace="System.Web.UI.MobileControls" Assembly="System.Web.Mobile" %>
<%@ Page Page language="c#" Inherits="System.Web.UI.MobileControls.MobilePage" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Web" %>
<%@ Import Namespace="System.Web.Mobile" %>
<%@ Import Namespace="System.Web.UI.MobileControls" %>
<Head>
<meta name="CODE_LANGUAGE" content="C#"></Head>
<script runat="server">
// Simple structure of e-mail struct MailInfo
{
public string subject;
public string sender;
public string content;
} MailInfo mailInfo; // 邮件信息全局实例
// Page_Load:
// 页面初始加载操作
void Page_Load(object sender, System.EventArgs e)
{
if (ViewState["Binded"] == null)
{
DataBind();
ViewState["Binded"] = true;
}
}
// 页面控件与数据邦定
override public void DataBind()
{
ListBindData();
}
// 列表项命令处理
void List_ItemCommand(object sender, ObjectListCommandEventArgs e)
{
switch (e.CommandName)
{
case "Details":
{
listMail.SelectListItem(e.ListItem.Index, true);//选择当前项目
listMail.ViewMode = ObjectListViewMode.Details; //设置详细试图模式
BindListDetailView(e.ListItem);
break;
}
}
}
// 列表项目详细页面与数据绑定
void BindListDetailView(ObjectListItem item)
{
mailInfo = new MailInfo();
mailInfo.subject = item["Subject"];
mailInfo.sender = item["Sender"];
mailInfo.content= item["Content"];
listMail.Details.DataBind();
}
// 列表对象数据榜定操作
void ListBindData()
{
listMail.DataSource = GetDemoData();
listMail.DataBind();
}
// 范例数据
DataTable GetDemoData()
{
DataTable data = new DataTable;
Data.Columns.Add("Subject", typeof(string));
Data.Columns.Add("Sender", typeof(string));
Data.Columns.Add("Content", typeof(string));
// 生成20个数据
for (int i = 1; i <= 20; i++)
{
DataRow r = data.NewRow();
r[0] = string.Format("Mail Subject {0}", i);
r[1] = string.Format("snd-addr{0}@google.com", i);
r[2] = "Template 应用示例";
data.Rows.Add(r);
}
return data;
}
</script>
<body Xmlns:mobile="http://schemas.microsoft.com/Mobile/WebForm">
<mobile:Form ID="Form1" Paginate="true" runat="server">
<mobile:ObjectList id="listMail" ItemsPerPage="10" CommandStyle-StyleReference="subcommand" LabelStyle-StyleReference="title"
OnItemCommand="List_ItemCommand" runat="server">
<mobile:DeviceSpecific runat="server">
<Choice Filter="isJScript">
<HeaderTemplate>
<table width="100%" border="0" cellspacing="2" cellpadding="0">
<tr> <td>主题</td> </tr>
<tr> <td><hr size="1"></td></tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td bgColor="#ccccff">
<asp:LinkButton runat="server" CommandName="Details" Text=<%# DataBinder.Eval(((ObjectListItem)Container).DataItem, "Subject") %>/>
</td>
</tr>
</ItemTemplate>
<AlternatingItemTemplate>
<tr>
<td bgColor="#99ffcc">
<asp:LinkButton runat="server" CommandName="Details" Text=<%# DataBinder.Eval(((ObjectListItem)Container).DataItem, "Subject") %>/>
</td>
</tr>
</AlternatingItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
<ItemDetailsTemplate>
<mobile:Label Text=<%# mailInfo.subject %> runat="server" />
<hr size="1"> 发送人:<a href="mailto:<%# mailInfo.sender %>" runat="server" /><br>
内容:<mobile:Label id="labTime" Text=<%# mailInfo.content %> runat="server" />
<hr size="1">
<center><a href="#" onclick="javascript:history.go(-1)">[ Back ]</a></center>
</ItemDetailsTemplate>
</Choice>
</mobile:DeviceSpecific>
</mobile:ObjectList>
</mobile:Form>
</body>
图4.1 应用Template
5. 一致的风格
在面向桌面的Web应用中,我们可以用CSS(cascading style sheets)来获得一致的界面风格。但是,到现在,对于几乎所有的移动设备的web请求,MobileCapabilities. SupportsCss都返回FALSE。不过,虽然设备不支持CSS,Asp.Net 依然有它的解决方法:MobileControl提供了StyleReference属性,以及StyleSheet, Style类和mobile:stylesheet, style扩展标记,可以让我们如同使用CSS一样来获得一致的界面风格。要获得关于style的详细信息,请参见.Net Framework document中的相关章节。表5.1是实现了MobileControl.StyleReference属性的Asp.net mobile Control 清单。
AdRotator Class
PagedControl Class
Calendar Class
Panel Class
Command Class
PhoneCall Class
CompareValidator Class
RangeValidator Class
CustomValidator Class
RegularExpressionValidator Class
Form Class
RequiredFieldValidator Class
Image Class
SelectionList Class
Label Class
TextBox Class
Link Class
TextControl Class
List Class
TextView Class
ObjectList Class
ValidationSummary Class
表5.1 支持StyleReference属性的Mobile Controls
Debug Environment
测试Asp.net Mobile工程不一定要在模拟器中运行,可以先在IE中调试,清除所有的语法及逻辑错误。然后再在模拟器中检查比较真实的运行效果,以及设备兼容性等问题(如果应用Asp.Net Mobile编写面向移动平台的Web应用,兼容性问题几乎可以不用考虑,这也正是Asp.Net Mobile目标之一)。在IE中运行和调试Asp.Net Mobile 工程与调试普通Asp.Net工程相同。
Asp.Net Mobile Vs Asp.Net
Asp.Net Mobile 与Asp.Net 之间的渊源和异同之处在上面的段落中已经说了许多了,这里做一个总结,并补充几个重要的条款。
1.Asp.Net面向支持基本一致的HTML标准的桌面浏览器;Asp.Net Mobile面向采用不同标准,表现能力各不相同的移动设备。
2.Asp.Net Mobile工程的Web.Config文件中需要配置deviceFilters,来区分不同的请求设备及它们的表现能力。
3.Asp.Net Mobile工程Web.Config文件的mobileControls节中配置用户定义控件时,需要设置目标内容生成适配器(adapter)。
4.在服务端,Asp.Net 工程采用Page.Response.Redirect来实现请求页面重定向,Asp.Net Mobile工程采用MobilePage. RedirectToMobilePage来实现请求页面的重定向。
5.在Asp.Net Mobile工程中,对于支持javascript和HTML的设备(譬如Pocket PC),可以应用Asp.Net 控件,但必须在被包含DeviceSpecific标记内部。
6.在编辑Asp.Net Mobile 页面时,不要在DeviceSpecific标记之外出现HTML标记,在生成目标内容时,这些标记都将被忽略。
总之,两者的共同点多于不同点,只要搞清了两者在页面设计与页面呈现上的区别,就可以将编写Asp.net应用的经验应用到Asp.net Mobile应用上。从某种角度上,可以将Asp.net 应用看成是面向一种设备(这种设备的功能超强)的Asp.net Mobile应用。
Mobile Browser
我们的页面最后将在移动设备的浏览器中呈现,对于Microsoft 的Pocket PC系列,其中的浏览器为Pocket IE,对于许多具有上网功能的国产手机,采用Openwave公司的Openwave浏览器。Mobile Browser种类繁多,采用标准也不一致,但主要采用两种脚本语言HTML(cHTML, HTML3.2)和WML。现面给出关于Pocket IE(Pocket PC2002)的比较详细的资料,更详细的资料参见MSDN站点。
语言标准
W3C HTML3.2, 不支持DHTML(与IE3.02标准相同)
执行脚本
JavaScript1.1(与IE4.0标准相同)
XML
支持DOM对象
cascading style sheets
不支持
有效区域大小
240*268
色彩
支持16位色/16级灰度
Cookie
支持
本地缓存
支持
表1.1 Pocket IE Features
Referencehttp://msdn.microsoft.com/library/