代码改变世界

深入剖析微软ASP.NET Ajax中的数据绑定架构上篇之二

2007-09-13 09:35  Jacky_Xu  阅读(467)  评论(0编辑  收藏  举报
三、命名空间Sys.Preview.UI.Data中的客户端控件

(一)ItemView控件

有时,我们需要向用户显示一个关于我们的集合项的详细视图,例如在一个购物应用程序中显示关于你的产品的细节信息。MS AJAX客户端控件ItemView控件能够帮助你实现这一特征,类似于ASP.NET服务器控件DetailsView对应的行为,但是它完全运行于客户端。该ItemView类以及ListView类都派生自基类—Sys.UI.Data.DataControl。

事实上,在命名空间Sys.Preview.UI.Data中存在若干客户端控件,例如DataControl(ItemView和ListView的父类),DataNavigator,ItemView,ListView,XSLTView等。

在此,我们仅关注两个控件—ItemView和ListView。注意,在开发中,类似于ASP.NET服务器控件GridView相对于ObjectDataSource,MS AJAX中的客户端控件ItemView(或ListView)正对应于DataSource。下列表格列出ItemView控件常用的和自定义的属性。

属性名

描述

id

标识ItemView控件。

canMoveNext

如果还存在下一条记录,则为true;否则为false。

canMovePrevious

如果还存在前一条记录,则为true;否则为false。

data

存储所有的加载到当前ItemView控件中的Sys.Preview.Data.DataTable对象—这些DataTable对象都是通过DataSource控件从后台获取的。

dataIndex

标识当前记录的索引号。

dataItem

基于dataIndex返回当前记录。

length

返回的记录总数。

itemTemplate

这个模板用于渲染列表中的单个项(例如使用一个<tr>标签)。它必须位于layoutTemplate模板内。

EmptyTemplate

这个模板用于当数据源中没有数据项时(或该ItemView仍然等待来自于服务器端的数据时)生成一个空消息。

ItemView控件中的常用方法

方法名

描述

addItem

把一个新项添加到客户端数据集合中,并且这个操作将使dataset变“脏”

deleteCurrentItem

从客户端数据集合中删除当前项,这个操作也将使dataset变“脏”

moveNext

移动到下一条记录,这个操作将再次触发定义于ItemTemplate中的控件的数据绑定

movePrevious

移动到前一条记录,这个操作也将再次触发定义于ItemTemplate中的控件的数据绑定

请注意上面所有的操作都发生于客户端—在此仅修改了客户端数据。因此,如果你想把所作的改变提交(保存)到服务器,那么,你必须调用DataSource控件中的相应方法。

显然,该ItemView总是用于在客户端显示一个记录,而接下来要讨论的ListView控件则用于列出符合某些条件的记录。

(二)ListView控件

类似于ASP.NET的GridView服务器控件,MS AJAX的ListView控件也提供了AJAX方式的客户端实现。尽管你可以使用传统型ASP.NET 2.0 GridView服务器控件,然后简单地添加一个MS AJAX UpdatePanel控件以便让你的GridView工作于AJAX方式,但是这种方法的效率并不高而且并非“纯”MS AJAX实现。因此,我们可以使用完全基于客户端的MS AJAX控件ListView来实现这一过程,并且效果更好。不必担心,ListView控件的操作十分类似于GridView提供一系列相关概念。但是注意,因为目前还没有针对这些内容的智能感知支持的IDE,所以,你必须十分细致地分析本文所附实例中的源码。

ListView控件中的常用属性

属性名 描述
Id 标识ListView控件。
canMoveNext 如果还存在下一条记录,则为true;否则为false
canMovePrevious 如果还存在前一条记录,则为true;否则为false
data ItemView控件一致
dataIndex 标识当前记录的索引值。
dataItem 基于dataIndex返回当前记录。
length 返回记录记录总数。
alternatingItemCssClass 指定可选项使用的css类。
layoutTemplate 这个模板用于生成列表容器(例如,使用一个<table>标签),头部(例如,使用一个<thead>标签)和页脚。你必须为一个ListView指定一个layoutTemplate。这个模板必须包含一个itemTemplate,也可以包含一个separatorTemplate
itemCssClass 指定各项所使用的css类。
itemTemplate 这个模板用于生成列表中单个项(例如,使用一个<tr>标签)。它必须包含于layoutTemplate内。
EmptyTemplate 这个模板用于当数据源中没有数据项时(或该ListView仍然等待来自于服务器端的数据时)生成一个空消息。
selectedItemCssClass 指定选择项。
seperatorCssClass 指定项分隔符对应的css类。
seperatorTemplate 这个模板用于生成列表中相邻两项间的一个分隔符(例如,使用一个<hr>标签)。它必须包含于layoutTemplate内。
itemTemplateParentElementID 这个属性用于定义itemTemplateseparatorTemplate的父元素。这样以来,记录项和分隔符即可反复出现于这个元素中(例如,使用一个<tbody>标签)。

就和ItemView一样,为了使用一个ListView控件,你必须提供给MS AJAX一些模板以便让它知道如何生成你的内容。实践中,这些模板通常相应于一些特定的HTML元素(例如div等),因此学习这部分内容时一定要特别仔细加以对照。

好,理论方面的讨论已经足够多了。在下一节中,我们将构建一个简单的示例来实际体验一下MS AJAX中的客户端数据绑定!

四、开始使用数据绑定—一个简单的例子

1、创建一个ASP.NET AJAX CTP-Enabled网站

启动Visual Studio 2005,然后选择菜单项“文件|新建网站…”,使用模板“ASP.NET AJAX CTP-Enabled网站”创建一个新的网站,并命名工程为AJAXCTPDev311(选择Visual C#作为内置语言)。此后,系统应该自动地添加对必要的程序集—Microsoft.Web.Preview.dll和System.Web.Extension.dll的参考。此外,你会注意到一个ScriptManager服务器控件自动地添加到页面中。注意,这个服务器控件作为整个ASP.NET AJAX框架的控制中心。

然后,稍经修改,页面Default.aspx看起来如图5所示:

图5:设计时刻的示例web页面

勿需多言,下面首先让我们来观察一下这个aspx页面相应的源代码:

列表4

<head runat="server">

<title>Client-Side Data Binding Test</title>

</head>

<body style="font-size: 12pt">

<form id="form1" runat="server">

<asp:ScriptManager

ID="ScriptManager1" runat="server" >

<Services>

<asp:ServiceReference

Path="BookDataService.asmx" />

</Services>

<Scripts>

<asp:ScriptReference Assembly="Microsoft.Web.Preview"

Name="PreviewScript.js" />

</Scripts>

</asp:ScriptManager>

<div style="text-align: left">

<span style="color: #0000cc"><span style="font-size: 24pt">

<span>

Client-Side Data Binding Test</span>

<br />

</span></span>

</div>

<br />

<div id="header">

<input type="button" id="Button5"

value="Get Book by Title" />

<br />

</div>

<div id="Book titles to be listed here">

</div>

<div id="Books"></div>

<div style="display:none;">

<div id="LayoutTemplate">

<div id="ItemTemplateParent">

<div id="ItemTemplate">

<span id="BookTitle"></span>

</div>

</div>

</div>

<div id="emptyTemplate">

empty...

</div>

</div>  
<script type="text/xml-script">

<page xmlns="http://schemas.microsoft.com/xml-script/2005">

<components>

<dataSource id="BooksDataSource"

serviceURL="BookDataService.asmx" />

<button id="Button5" >

<click>

<invokeMethodAction

target="BooksDataSource" method="load" />

</click>

</button>

<listView id="Books"

itemTemplateParentElementId="ItemTemplateParent">

<bindings>

<binding dataContext="BooksDataSource" dataPath="data"

property="data" />

</bindings>

<layoutTemplate>

<template layoutElement="LayoutTemplate" />

</layoutTemplate>

<itemTemplate>

<template layoutElement="ItemTemplate">

<label id="BookTitle">

<bindings>

<binding dataPath="Title" property="text" />

</bindings>

</label>

</template>

</itemTemplate>

<emptyTemplate>

<template layoutElement="emptyTemplate" />

</emptyTemplate>

</listView>

</components>

</page>

</script>

</form>

</body>

在此,有几点需要强调一下:

①必须在ScriptManager控件下添加对必要的.asmx及.js文件的参考;

②我们定义了若干span和div HTML元素以作为MS AJAX客户端控件—ListView的占位符。如前所述,ListView提供有好几个有用的模板—layoutTemplate,itemTemplate,separatorTemplate,emptyTemplate,和一个必要的属性—itemTemplateParentElementId(指定temTemplate和separatorTemplate的父元素;通过这种方式,该itemTemplate和separatorTemplate相关联的元素都可以在其中反复生成);

③接下来,我们进行了声明性编程(在下篇中再详细讨论它)。为了实现把从web服务端返回的数据显示于ListView控件中,我们必须使用DataSource控件来指定这个服务的URL;

④我们定义了一个ListView框架,相应的模板对应于它们各自的HTML对应元素;

⑤在步骤④中,我们还建立了对web服务内的属性的绑定;

⑥最后,细心的读者应该还会注意到,我们在此使用声明性方式来调用按钮的点击事件处理器,它又进一步调用DataSource控件BooksDataSource的load方法。

2、创建一个Web服务

接下来,我们将使用声明性方式写一个web服务以便从浏览器端消费它。在本例中,我们让该服务返回一个Book对象数组。

右击工程并选择“添加新项”,然后创建一个新的Web服务,并命名为为BookDataService.asmx。然后,在文件BookDataService.cs中,我们要编写我们的WebMethod—GetTitles。下面的列表5展示了其中重要的代码片断:

列表5

using System.Collections.Generic;

using System.ComponentModel;

…………

using System.Data;

using System.Web.Script.Services;

using Microsoft.Web.Preview.Services;

[WebService(Namespace = "http://tempuri.org/")]

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

[ScriptService]

public class BookDataService : DataService

{

public BookDataService()

{

//InitializeComponent();

}

[DataObjectMethod(DataObjectMethodType.Select)]

public Book[] GetTitles()

{

List _data = new List();

_data.Add(new Book("Hello,this is Title 1"));

_data.Add(new Book("Hello,this is Title 2"));

_data.Add(new Book("Hello,this is Title 3"));

_data.Add(new Book("Hello,this is Title 4"));

return _data.ToArray();

}

public class Book

{

private string _title;

public Book(){}

[DataObjectField(true)]

public string Title

{

get { return _title; }

set { _title = value; }

}

public Book(string title)

{

_title = title;

}

}

}

在此,有几点需要强调一下:

①根据有关资料,我们必须把属性ScriptService置于这个Web服务之前,这样才会使MS AJAX框架能够从客户端对它进行调用;

②我们令这个web服务派生自一个有些特殊的WebService—DataService,我们将在下篇中来讨论它;

③还要注意方法GetTitles前面使用一个特别的属性DataObjectMethod(定义于命名空间System.ComponentModel中)进行了修饰。这个属性含有两个参数—第一个是DataObjectMethodType,允许你指出是否此方法用于删除,插入,选择,填充或更新一个项;第二个属性(一个boolean值)用于指示是否某个方法是相应于它的操作类型的缺省方法。

④在此,还出现了另一个属性—DataObjectField。这个属性使用了三个参数以允许你指定:是否该属性是一个主键和一个自动增量值,它的字节长度,以及是否它可以为空。

现在,我们已经明确WebMethodGetTitles将返回一个Book对象数组。

3、消费Web服务

事实上,这项任务已经实现了。真的吗?是的。因为根据我们在前面对控件DataSource的load方法的解释,当你点击按钮“Get Book by Title”时,数据源BooksDataSource的方法load即被调用,然后,借助于修饰符[DataObjectMethod(DataObjectMethodType.Select)],WebMethod GetTitles被调用。最后,ListView Books被使用从WebMethod GetTitles返回的数据加以填充。

4、运行示例

如果没有什么问题的话,按F5并启动这个示例。然后,点击按钮“Get Book By Title”,你将看到如图6所示的运行时刻屏幕快照。

图6:示例程序运行时刻快照

【重要提示】为了正确运行这个示例,你还必须在配置文件web.config内添加下列转换器。

列表 6

 

至此,我们已经匆忙地介绍完一个简单的示例!

五、总结

在这个上篇中,我们首先概括介绍了MS AJAX框架中的数据绑定架构,然后我们较细致了分析了主要的用于实现的的客户端控件及其相互间的关系。最后,我们通过一个简单的示例给出MS AJAX框架中的数据绑定架构在实践的应用。在下篇中,我们将进一步分析两个更为复杂的示例以进一步挖掘MS AJAX客户端数据绑定所蕴含的思想。