运用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,如下:
1<devicefilters>
2<filter argument="J-Phone" compare="Type" name="isJPhone"></filter>
3<filter argument="html32" compare="PreferredRenderingType" name="isHTML32"></filter>
4<filter argument="wml11" compare="PreferredRenderingType" name="isWML11"></filter>
5<filter argument="chtml10" compare="PreferredRenderingType" name="isCHTML10"></filter>
6<filter argument="Go.Web" compare="Browser" name="isGoAmerica"></filter>
7<filter argument="Microsoft Mobile Explorer" compare="Browser" name="isMME"></filter>
8<filter argument="MyPalm" compare="Browser" name="isMyPalm"></filter>
9<filter argument="Pocket IE" compare="Browser" name="isPocketIE"></filter>
10<filter argument="Phone.com 3.x Browser" compare="Type" name="isUP3x"></filter>
11<filter argument="Phone.com 4.x Browser" compare="Type" name="isUP4x"></filter>
12...
13<filter argument="true" compare="Cookies" name="supportsCookies"></filter>
14<filter argument="true" compare="Javascript" name="supportsJavaScript"></filter>
15<filter argument="true" compare="CanInitiateVoiceCall" name="supportsVoiceCalls"></filter>
16</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是如此的重要,需要我们专门用一节来讨论。
1<mobile:devicespecific id="DeviceSpecific1" runat="server">
2<choice filter="isHTML32">
3<headertemplate>
4<table bgcolor="blue" border="1">
5<tr>
6<td>This is Cell1</td>
7<td>This is Cell2</td>
8</tr>
9</table>
10</headertemplate>
11</choice>
12<choice filter="">
13<headertemplate>
14<mobile:label runat="server" text="This is Cell1"></mobile:label>
15<mobile:label runat="server" text="This is Cell2"></mobile:label>
16</headertemplate>
17</choice>
18</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标记开始处被呈现 |
1<form id="Form1" …=""> {header content}
2Footer 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展现邮件列表的方法。
1@ Register TagPrefix="mobile" Namespace="System.Web.UI.MobileControls" Assembly="System.Web.Mobile"
1@ Page Page language="c#" Inherits="System.Web.UI.MobileControls.MobilePage"
1@ Import Namespace="System.Data"
1@ Import Namespace="System.Web"
1@ Import Namespace="System.Web.Mobile"
1@ Import Namespace="System.Web.UI.MobileControls"
1<head>
2<meta content="C#" name="CODE_LANGUAGE"/></head>
1<script runat="server">
2// Simple structure of e-mail struct MailInfo
3{
4public string subject;
5public string sender;
6public string content;
7} MailInfo mailInfo; // 邮件信息全局实例
8
9// Page_Load:
10// 页面初始加载操作
11void Page_Load(object sender, System.EventArgs e)
12{
13if (ViewState["Binded"] == null)
14{
15DataBind();
16ViewState["Binded"] = true;
17}
18}
19
20// 页面控件与数据邦定
21override public void DataBind()
22{
23ListBindData();
24}
25// 列表项命令处理
26void List_ItemCommand(object sender, ObjectListCommandEventArgs e)
27{
28switch (e.CommandName)
29{
30case "Details":
31{
32listMail.SelectListItem(e.ListItem.Index, true);//选择当前项目
33listMail.ViewMode = ObjectListViewMode.Details; //设置详细试图模式
34BindListDetailView(e.ListItem);
35break;
36}
37}
38}
39// 列表项目详细页面与数据绑定
40void BindListDetailView(ObjectListItem item)
41{
42mailInfo = new MailInfo();
43mailInfo.subject = item["Subject"];
44mailInfo.sender = item["Sender"];
45mailInfo.content= item["Content"];
46listMail.Details.DataBind();
47}
48// 列表对象数据榜定操作
49void ListBindData()
50{
51listMail.DataSource = GetDemoData();
52listMail.DataBind();
53}
54// 范例数据
55DataTable GetDemoData()
56{
57DataTable data = new DataTable;
58Data.Columns.Add("Subject", typeof(string));
59Data.Columns.Add("Sender", typeof(string));
60Data.Columns.Add("Content", typeof(string));
61// 生成20个数据
62for (int i = 1; i <= 20; i++)
63{
64DataRow r = data.NewRow();
65r[0] = string.Format("Mail Subject {0}", i);
66r[1] = string.Format("snd-addr{0}@google.com", i);
67r[2] = "Template 应用示例";
68data.Rows.Add(r);
69}
70return data;
71}
72</script>
1<body xmlns:mobile="http://schemas.microsoft.com/Mobile/WebForm">
2<mobile:form id="Form1" paginate="true" runat="server">
3<mobile:objectlist commandstyle-stylereference="subcommand" id="listMail" itemsperpage="10" labelstyle-stylereference="title" onitemcommand="List_ItemCommand" runat="server">
4<mobile:devicespecific runat="server">
5<choice filter="isJScript">
6<headertemplate>
7<table border="0" cellpadding="0" cellspacing="2" width="100%">
8<tr> <td>主题</td> </tr>
9<tr> <td><hr size="1"/></td></tr>
10</table></headertemplate>
11<itemtemplate>
12<tr>
13<td bgcolor="#ccccff">
14<asp:linkbutton "subject")="" #="" ```="" commandname="Details" databinder.eval(((objectlistitem)container).dataitem,="" runat="server" text="```"></asp:linkbutton>
15</td>
16</tr>
17</itemtemplate>
18<alternatingitemtemplate>
19<tr>
20<td bgcolor="#99ffcc">
21<asp:linkbutton "subject")="" #="" ```="" commandname="Details" databinder.eval(((objectlistitem)container).dataitem,="" runat="server" text="```"></asp:linkbutton>
22</td>
23</tr>
24</alternatingitemtemplate>
25<footertemplate>
26
27</footertemplate>
28<itemdetailstemplate>
29<mobile:label #="" ```="" mailinfo.subject="" runat="server" text="```"></mobile:label>
30<hr size="1"/> 发送人:<a href="mailto:```
31# mailInfo.sender
32```" runat="server"></a><br/>
33内容:<mobile:label #="" ```="" id="labTime" mailinfo.content="" runat="server" text="```"></mobile:label>
34<hr size="1"/>
35<center><a href="#" onclick="javascript:history.go(-1)">[ Back ]</a></center>
36</itemdetailstemplate>
37</choice>
38</mobile:devicespecific>
39</mobile:objectlist>
40</mobile:form>
41</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