You are on page 1of 114

Atlas 学习指南 Dflying http://dflying.cnblgos.

com

Altas 学习指南

Dflying

http://dflying.cnblogs.com

博客园 @ Dflying i
Atlas 学习指南 Dflying http://dflying.cnblgos.com

目 录
ALTAS学习指南 ............................................................... I

第一章 ATLAS基础篇 ...................................................... 1


A. Atlas UpdatePanel简要介绍.......................................... 1
B. Atlas UpdatePanel使用技巧以及常见问题 .............................. 2
C. 绑定(Binding).................................................... 4
第二章 SYS.DATA命名空间.................................................. 9
A. DataSource和XMLDataSource.......................................... 9
B. DataColumn、DataRow和DataTable .................................... 12
C. DataView和DataFilter.............................................. 14
第三章 ATLAS数据控件介绍 ............................................... 17
A. 使用ASP.NET Atlas ListView控件显示列表数据 ........................ 17
B. 使用ASP.NET Atlas ItemView控件显示集合中的单个数据 ................ 22
C. 使用ASP.NET Atlas PageNavigator控件实现客户端分页导航 ............. 33
D. 使用ASP.NET Atlas SortBehavior实现客户端排序 ...................... 41
E. 使用ASP.NET Atlas XSLTView控件用XSLT修饰并显示XML数据 ............. 49
第四章 ATLAS实战篇 ..................................................... 54
A. 显示真实进度的ProgressBar(进度条)控件 ........................... 54
B. 创建自定义的Action................................................ 62
C. 创建自定义的Behavior.............................................. 65
D. 创建自定义的Transformer........................................... 70
E. 创建自定义的Validator............................................. 73
F. 随输入内容自动调整行数的Textarea .................................. 77
G. 实现拖放(Drag & Drop)效果(上)..................................... 79
H. 实现拖放(Drag & Drop)效果(下)..................................... 80
I. In Place Editing输入控件.......................................... 87
第五章 ATLAS其它篇 ..................................................... 93
A. 在Atlas服务器端实现中推荐使用Web Service而不是Page Method ......... 93
B. 调试Atlas客户端JavaScript脚本..................................... 95
C. The XMLHttpRequest Object........................................ 100

博客园 @ Dflying 版权所有 ii/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

第一章 Atlas 基础篇

A. Atlas UpdatePanel 简要介绍

UpdatePanel 是 ASP.NET Atlas 中很重要的一个控件。它把传统的 ASP.NET 程序与最新的 Web 2.0 AJAX


无缝的连接在一起。如果你已经有一些基于 ASP.NET 的网站,UpdatePanel 可以让你通过很小的修改轻松
的实现 AJAX。如果你并不很熟悉 AJAX 相关的技术比如 JavaScript/DOM 等,UpdatePanel 更是可以让
你不用书写一行客户端脚本而实现酷酷的 AJAX 应用。所需要的就是把需要动态更新的部分放置于一个
UpdatePanel 中,这一点与 MagicAjax Framework 有着异曲同工之妙。

使用 UpdatePanel 很简单,只需要如下几个步骤:

用 ASP.NET 实现你的设计,此刻你并不需要考虑任何有关 AJAX 的问题,就像普通的 ASP.NET 程序一样。

在页面上添加一个 ScriptManager 对象,并设定属性 EnablePartialUpdates=true

将你希望动态更新的部分用 UpdatePanel 包围起来

为你添加的 UpdatePanel 设定 Event Trigger

只要这些步骤就够了,不需要考虑 XMLHTTPRequest 或者 ActiveX 对象,也不需要书写客户端的脚本或者

考虑如何与服务器通信,所有的细节,Atlas 已经为你做好了。

Atlas UpdatePanel 的实现也很简单:浏览器如同普通 PostBack 一样 Post 回服务器,服务器处理后再次


发送给浏览器,这个过程就和传统的页面模型一样。但到达客户端时 ScriptManager 只更新位于
UpdatePanel 中的内容和 ViewState。

使用 UpdatePanel 中应该注意的几个问题:

必须指定 ScriptManager 中的属性 EnablePartialUpdates=true,这样 ScriptManager 才会将普通的


PostBack 转化为对服务器的异步调用,也就是 AJAX 的方法。否则页面只会与传统的 ASP.NET 一样刷新。

其次,UpdatePanel 提供两种引发异步 PostBack 的 Trigger:

• ControlValueTrigger:当某个控件的某个指定的属性变化时更新。例如:ControlID="dropDownList1"

PropertyName="SelectedValue"

• ControlEventTrigger:当某个控件发出指定事件时更新。例如:ControlID="button1"

EventName="Click"

最后,每个 UpdatePanel 都有两种更新的方式:

• Always:每次 AJAX PostBack 或是普通 PostBack 的时候都会更新该 Panel 的内容

• Conditional:只有满足如下某一条件时才更新该 Panel 的内容:

1. 当 Panel 中的某个控件引发了 PostBack 时

2. 当 Panel 所指定的某个 Trigger 被引发时

博客园 @ Dflying 1
Atlas 学习指南 Dflying http://dflying.cnblgos.com

3. 当 Panel 的 Update()方法在 Codebehind 中被调用时

一小段 UpdatePanel 的例子

<atlas:ScriptManager ID="ScriptManager1" EnablePartialRendering="true" runat="server" /

>

2 <atlas:UpdatePanel ID="up1" runat="server">

3 <Triggers>

4 <atlas:ControlValueTrigger ControlID="dropDownList1" PropertyName="SelectedValu

e" />

5 <atlas:ControlEventTrigger ControlID="button1" EventName="Click" />

6 </Triggers>

7 <ContentTemplate>

8 Content Here. e.g. TextBox, GridView

9 </ContentTemplate>

10 </atlas:UpdatePanel>

11

另外还有两个有用的 Atlas 特性:UpdateProgress 控件可以在更新的等待时间自动显示一段提示信息,可


以是一段“更新中……”文字也可以是 GIF 图像或者是更复杂的定制的内容。还有 Atlas 提供的错误处理机制,
以便集中处理更新中可能发生的错误。目前有很多 AJAX 程序的错误处理机制设计的并不是很好,包括
Windows Live Mail。

B. Atlas UpdatePanel 使用技巧以及常见问题

好多开发人员将会从 UpdatePanel 控件开始慢慢接触 Atlas。UpdatePanel 功能强大并且使用简单,


同时也拉近了我们和 Atlas 的距离。

我曾在此发表了一个对UpdatePanel的简要介绍
(http://dflying.cnblogs.com/archive/2006/03/25/358547.html)并得到了很多的反馈与问题。我
想有必要把这些问题以及有关UpdatePanel的使用技巧总结成一个帖子。希望能有所帮助。在这里感谢阿不,
dudu以及所有提出问题或参与讨论的朋友,让我对UpdatePanel有更深的认识。

首先,最重要的事情就是关注Atlas的老家:http://atlas.asp.net/。我们知道Atlas是一个新的,正在开发
中的Framework,每月,甚至每周都在发生着变化,所以作为一个Atlas开发人员,经常关注
http://atlas.asp.net/是必须的,你会得到最新的消息,最新的特性以及最新的演示程序。对于新手,

博客园 @ Dflying 版权所有 2/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

http://atlas.asp.net/docs提供了Atlas的API,Class文档可作参考(尚未全部完成,请多加关注)。下面
还有一些Atlas以及ASP.NET的核心人物的个人网站/blog,同样值得经常访问(英文):

1. http://blogs.msdn.com/brada/

2. http://weblogs.asp.net/scottgu/

3. http://www.nikhilk.net/

4. http://weblogs.asp.net/bleroy/

5. http://blogs.msdn.com/jhawk/

Atlas UpdatePanel 服务器控件使用技巧:

1. 务必设定 ScriptManager 的 EnablePartialRendering 属性为 true。有好多人向我抱怨说他

们的 UpdatePanel 并不以 AJAX 的方式工作而还是引发普通的整页 PostBack,原因就在于没有设

定这个属性。

2. 设定触发 UpdatePanel 的控件为服务器控件。因为无论 ControlValueTrigger 还是

ControlEventTrigger,指定的属性/事件都是服务器端属性/事件,都只在服务器端属性变化或

是服务器端发出事件时才能触发 UpdatePanel 的 PostBack。

3. 区别UpdatePanel的两种更新方式:Always和Conditional。请参考:

http://dflying.cnblogs.com/archive/2006/03/25/358547.html。我们应该设定正确的更新方

式以避免更新不必要更新的Panel,造成不必要的性能/网络开销。

4. 不要只使用 UpdatePanel。如果你从头开始建立一个 Atlas 程序,仅仅使用 UpdatePanel 来实现

AJAX 可能并不是最好的选择。UpdatePanel 仅仅简单的从头渲染所有的位于 ContentTemplate

内部的控件,在某些情况下可能非常低效,例如,对于一个包含了一个有相当多结点的 TreeView 控

件的 UpdatePanel 来说,如果你只是想简单的添加一个新节点,使用 UpdatePanel 将会从后台取

得整个 TreeView 并重新渲染,远不及仅存储后并把这个新的节点添加到 TreeView 中来得高效。在

这些情况下,你最好考虑使用一些较高级的 Atlas 客户端控件。当然,这也加大了一些开发的难度。

5. 在页面的 InitComplete 事件被引发前必须保证 UpdatePanel 已经被初始化。也就是说,不能

将 UpdatePanel 放置于比如一个 DataList 的 HeaderTemplate 中,因为 HeaderTemplate 中的

内容是在 Databinding 时期才得到的,而这时页面的 InitComplete 事件早已经结束。

6. 在 UpdatePanel 中不要使用 Response.Write(); 。这会扰乱 UpdatePanel 的执行过程。

博客园 @ Dflying 版权所有 3/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

7. Atlas 的客户端脚本可以使用于任何的开发平台/语言中。例如 ASP.NET 1.1,纯 HTML 甚至 PHP,

但是像 UpdatePanel 这样的服务器端控件只能用于 ASP.NET 2.0 页面中。Atlas 的客户端脚本实际

上就是一些经过组织的 JavaScript 文件,当然是与服务器端选用的技术无关的。但当你使用非

ASP.NET 2.0 环境时,需要手动加入对这些 JavaScript 文件的引用,因为你无法使用 ASP.NET 2.0

中的服务器端控件 ScriptManager。

8. 小心在 UpdatePanel 中包含第三方 JavaScript 实现的组件。开发跨平台的 JavaScript

Framework 是一件很艰巨的任务,在目前的 Atlas 实现中仍有很多兼容性的问题。让我们期待未来

会更好或者干脆现在想办法自己解决吧。

同时,在页面上添加一个 UpdateProgress 服务器端控件将会使用户了解你的程序在做什么。下面顺

便提一些 UpdateProgress 控件的使用技巧:

1. 在页面上添加一个且只添加一个 UpdateProgress 控件。UpdateProgress 控件应当是一个全局

的控件,所有的 AJAX 操作都会自动地由 UpdateProgress 控件来处理。想象一下如果 Gmail 一下

子显示了好多个 Loading 提示,用户一定会不知所措吧。

2. 在 UpdateProgress 的 Template 中有一个 magic ID:abortButton,你可以提供一个服务器

端 Button 或者 LinkButton 控件并指定 ID 为 abortButton,使用户可以取消当前执行的 AJAX 请

求。当然,使用 magic ID 并不是一个好的设计方法,相信在未来的版本中这个 magic ID 会被一个

类似<CancelTemplate>的东西取代。当然,在当前的 Atlas 版本中,请记住 abortButton。

C. 绑定(Binding)

Atlas架构提供了一种比ASP.NET中数据绑定(data binding)强大得多的客户端绑定模型。这种模型
异常灵活,甚至有些类似WPF(Windows Presentation Foundation)中的绑定模型。Atlas提供的
绑定模型允许您将某对象的任意一个属性绑定到另外一个对象的任意一个属性上。它不单单可以应用于
数据绑定,甚至可以将某个控件的样式绑定到另外一个控件上。这样使得在 Atlas中将一切关联起来变
成可能。

在这个帖子中,我将尝试分析一些 Atlas实现代码来解释 Atlas是如何完成Binding的。

首先让我们察看一小段应用 Atlas Binding的代码。这里将一个textbox的text属性和一个select list的


selectedValue属性绑定起来。无论你改变其中的哪个,在另一个上面都会有立刻得到体现。

(注意必须声明一个ScriptManager服务器端对象,以引入 Atlas
HTML和ASPX,定义textbox和select list。
必须的JavaScript文件。)

博客园 @ Dflying 版权所有 4/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

<atlas:ScriptManager ID="ScriptManager1" runat="server" />


<div>
Input an integer from 1 to 5.<br />
<input id="myTextBox" type="text" /><br />
Select an item.<br />
<select id="mySelect">
<option value="1">value 1</option>
<option value="2">value 2</option>
<option value="3">value 3</option>
<option value="4">value 4</option>
<option value="5">value 5</option>
</select>
</div>

Atlas脚本,将上面两个HTML控件“升级”成 Atlas控件。

<page xmlns:script="http://schemas.microsoft.com/xml-script/2005">
<references>
</references>
<components>
<textBox id="myTextBox">
<bindings>
<binding dataContext="mySelect" dataPath="selectedValue" property="text"
direction="InOut" />
</bindings>
</textBox>
<select id="mySelect" />
</components>
</page>

如上所示,我们只需要书写一小段简单的代码即可实现需要的绑定功能。

Atlas是如何实现这些的呢?首先,Atlas需要有一种途径来监听绑定控件的绑定属性的变化(除非你不
需要 Atlas提供的自动绑定功能)。在 Atlas.js中定义了一个名为Sys.INotifyPropertyChanged的接
口,类似.NET中提供的一样。对象可以实现这个接口以期让别的对象监听到自己的属性值的变化。Atlas
中所有组件的基类,Sys.Component,实现了这个接口。Sys.Component同样提供一个方法
raisePropertyChanged(propertyName),这个方法应该在每个属性的setter中被调用以发出
INotifyPropertyChanged.propertyChanged事件。

博客园 @ Dflying 版权所有 5/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

目前为止,我们可以看一下 Atlas控件中textbox的具体实现。看看textbox中是如何在相应的HTML事件发
出时同样发出propertyChanged事件的。

var _text;
var _changeHandler;

this.get_text = function() {
return this.element.value;
}

this.set_text = function(value) {
if (this.element.value != value) {
this.element.value = value;
this.raisePropertyChanged('text');
}
}

this.initialize = function() {
Sys.UI.TextBox.callBaseMethod(this, 'initialize');

_text = this.element.value;

_changeHandler = Function.createDelegate(this, this._onChanged);


this.element.attachEvent('onchange', _changeHandler);

_keyPressHandler = Function.createDelegate(this, this._onKeyPress);


this.element.attachEvent('onkeypress', _keyPressHandler);
}

this._onChanged = function() {
if (this.element.value != _text) {
_text = this.element.value;
this.raisePropertyChanged('text');
}
}

可以看到,当text属性改变时,Atlas发出了propertyChanged事件,这就使绑定到这个属性成为可能。

而后 Atlas的绑定模型捕获到了这个事件,再根据binding声明查找出与其相关的目的对象以及相应的属性,
并调用这个属性的Setter来实现目的对象属性的变化。

如果源对象(source object)实现了INotifyPropertyChanged接口,并且改变的属性就是dataPath 中指

博客园 @ Dflying 版权所有 6/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

定的属性,同时direction 设定为In或者InOut,Atlas绑定将通过分析引入(incoming)的binding来处

理propertyChanged事件(参考下面将要介绍的evaluateIn()方法)。

类似的,如果目的对象(target object)实现了INotifyPropertyChanged接口,并且改变的属性就

是property中指定的属性,同时direction 设定为Out或者InOut,Atlas绑定将通过分析流出

(outgoing)的binding来处理propertyChanged事件(参考下面将要介绍的evaluateOut()方法)。

接下来让我们察看binding实现代码中的的公有方法和属性来分析一下 Atlas绑定的核心实现。在这里没有必

要列出涉及绑定的全部代码,如果您感兴趣,可以用关键词Sys.BindingBase和Sys.Binding 在 Atlas.js

文件中进行搜索。首先是Sys.BindingBase提供的方法和属性。

1. 属性 automatic:指定当源对象的相应属性变化时(对于 In 和 InOut)
,或者目的对象的相应属性

变化时(对于 Out 和 InOut)


,绑定是否将被自动执行。这个属性默认会被置为 true。当然如果你

需要完全控制绑定的开始时机时也可以设定为 false。例如,某些情况下你决定在一个 AJAX 请求成

功返回的时候才开始绑定数据源与显示控件,以确保显示控件真正绑定到了一些数据,这时你需要显

示的调用 binding 的 evaluate()方法以开始绑定。

2. 属性 dataContext:指定拥有待绑定属性的对象。如果不指定的话,Atlas binding 将调用包含它

的父控件的 dataContext 属性代替。控件可以通过返回设定的 dataContext 或是按照默认返回其

父控件的 dataContext 来实现这个属性。例如,某个 ListView 控件可以在其创建 ListView Item

时设定它的 dataContext 为一个 DataRow 对象,以实现绑定。

3. 属性 dataPath:指定需要绑定的源对象的属性。Atlas binding 还允许绑定一个嵌套的属性,类似:

sourceObjectProperty.nestedProperty.nestedNestedProperty。源代码中可以看出 Atlas 能自

动为你转化并运行这些代码。dataPath 属性的默认值为空,也就是 Atlas 会绑定这个对象本身。

4. 属性 property:指定需要绑定的目标对象的属性。你应该总是指定这个属性,否则这个绑定就没有

任何意义。

5. 属性 propertyKey:有时候我们可能需要绑定到某个对象的嵌套属性上。比如,如果需要绑定到

style 的属性 color,我们可以指定 property 属性为 style,并指定 propertyKey 属性为 color。

6. 属性 transformerArgument:传递给 Atlas transformer 的参数,只有设定 transform 时才

会用到。

7. 事件 transform:这个事件允许在绑定时指定一个 transformer。当你需要在绑定的时候对数据做

以处理时,transformer 将会是个很好的选择。例如,如果你希望显示一个布尔值为 Yes/No 而不

博客园 @ Dflying 版权所有 7/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

是默认的 true/false,那么就应该使用一个自定义的 transformer。Atlas 同时提供了一些内建的

transformer,例如 Add,Multiply 以及 Compare 等。

8. 方法 evaluateIn:处理引入的 binding。如果 direction 属性设置成为 In 或者 InOut,该方法将

取得源对象的属性的值(根据 binding 中设定的 dataContext 以及 dataPath 属性)


,并调用目标

对象相应属性的 Setter。这也就是 Atlas 中实现 binding 的核心部分。

Sys.Binding(也在 Atlas.js中)中也有一些重要的方法/属性:

1. 属性 direction:指定希望监听的属性变化的方向。可以设定为 In,Out 或者 InOut。默认值为

In。

2. 方法 evaluateOut:与基类中的方法 evaluateIn 类似,但是以相反的方向执行。当然,需要将

directiton 属性设定为 Out 或者 InOut。

希望这些解释能够让您对 Atlas的“神奇的”绑定有一些更深入的理解。欢迎留言探讨。

PS:这篇文章中有些英文不知道应该如何用中文表示,希望能得到一些建议以及指正:

1. evaluate,我翻译成“处理”,但文中还有“计算求值”的意思,这一点没有体现出来。

2. incoming 和 outgoing,我翻译成“引入”和“流出”……觉得不是一般的别扭。

3. transformer,没有翻译(实在不知道怎么说了)。

4. getter 和 setter,没有翻译(一直都不知道怎么翻译)。

博客园 @ Dflying 版权所有 8/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

第二章 Sys.Data 命名空间

A. DataSource 和 XMLDataSource

目前为止,对于 ASP.NET Atlas 的命名空间 Sys.Data 中的客户端控件,国外以及国内均无较完备的介绍或

官方文档,而在目前的 Web 应用程序开发中数据访问又是如此重要的一部分。所以我希望能在这里分享一些

我的关于这部分控件的使用心得与经验,希望对各位能有所帮助。请注意这个系列仅仅是一些介绍,也就是

说,这里我会主要谈论一些如何使用的方法,而不会过多涉及到这些控件是如何实现的以及它们的工作原理。

如果您对这些较高级的话题感兴趣,我会在未来的文章中有所涉及。但个人感觉目前的首要任务还是普及

Atlas,从基本的使用介绍入手。同时,我本人也处在学习 Atlas 的过程中,文章中难免有不解,疏漏甚至错

误的部分,这里还请您不吝指出。也欢迎留下您的宝贵看法。

OK,开头部分废话到此为止,让我们切入正题。

在实际开发的 Web 应用程序中,我们大都需要与数据打交道:从后台取出数据并显示给用户,然后把用户的

修改提交回数据库保存。这也构成了当今 Web 应用程序的大部分内容,所以 ASP.NET 把以上的操作抽象出

来并作为内建的 DataSource 对象提供给我们开发者。Atlas 脚本库也提供了相应的客户端 DataSource 对

象。

在 ASP.NET Atlas 中,有两种 DataSource 对象:

1. Sys.Data.DataSource:描述一个表格状数据结构的数据源,例如查询数据库得到的一个集合。

DataSource对象与ASP.NET中的SQLDataSource类似,可用来作为Atlas客户端控件ListView(请

参考:使用ASP.NET Atlas ListView控件显示列表数据 )和ItemView(请参考:使用ASP.NET Atlas

ItemView控件显示集合中的单个数据 )的客户端数据源。您可以使用DataSource对象从服务器端

取得数据并把用户的修改提交回服务器保存。

2. Sys.Data.XMLDataSource::描述一个层次状数据结构的数据源,例如一个 XML 文档。

XMLDataSource 对象与 ASP.NET 中的 XMLDataSource 对象类似,可用来作为 Atlas 客户端控

件 XSLTView(介绍待完成)的客户端数据源。与 DataSource 数据源不同的是,XMLDataSource

只能读取数据,不能将用户的改变提交回服务器。

下面我来依次介绍这两个数据源:

博客园 @ Dflying 版权所有 9/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

Sys.Data.DataSource

DataSource 数据源有如下属性:

1. data:从服务器端取回并保存在客户端的数据。

2. autoLoad:布尔值,用来指定当这个数据源被初始化之后是否自动开始从服务器端取得数据。如

果您需要在页面加载时就指定该数据源的内容,应该使用 initialData 属性代替,因为它避免了自

动加载带来的在页面被加载后立刻发生的那一次与服务器的通信。

3. initialData:随着页面加载而同时被送往数据源的数据。在好多情况中,当用户第一次访问某个页

面时候就需要使用一些初始的数据,例如某个列表的第一页的记录。这时候我们可以使用 Atlas 的服

务器端控件 InitialData 来将这部分数据与页面源文件一起,在这次 HTTP 请求中发送给客户端,以

避免在页面传输完成后立刻发生第二次请求。

4. isDirtyAndReady:表示该数据源是否完成了从服务器端的加载,且取得到了不为空的数据集合,

且数据没有被修改过。

5. isReady:表示该数据源是否完成了从服务器端的加载。您可以将这个属性绑定到您的数据显示控

件的 enabled 属性上,这样在数据源加载的过程中数据显示控件将被禁用,以避免误用户的操作。

6. rowCount:数据的条目数。

7. serviceURL:数据源请求数据的 Web Service 的 URL。您必须提供这个属性。

8. parameters:Web Service 的参数。仅当 serviceType 属性为 Handler 时才需要设置。

9. serviceType:服务器端 Service 的类型。可选 DataService 或 Handler。默认值与推荐值是

DataService,代表您的 Service 类继承于 Microsoft.Web.Services.DataService,拥有

内建的 CRUD 方法调用机制。

DataSource 数据源有如下方法:

1. load:从服务器取得数据。

2. save:将客户端对数据的修改提交给服务器保存。只在 serviceType 属性设置成 DataService 时

候有效。

DataSource 数据源有如下事件:

1. dataAvailable:将在成功取得数据后被引发。

博客园 @ Dflying 版权所有 10/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

DataSource数据源的示例请参考:使用ASP.NET Atlas ListView控件显示列表数据 和 使用


ASP.NET Atlas ItemView控件显示集合中的单个数据。

Sys.Data.XMLDataSource

XMLDataSource 数据源有如下属性:

1. autoLoad:布尔值,用来指定当这个数据源被初始化之后是否自动开始从服务器端取得数据。与

DataSource 数据源类似,如果您需要在页面加载时就指定该数据源的内容,应该使用

initialDocument 属性代替。

2. data:XML 数据,解析自 document 属性值。

3. document:从服务器端取得的包含 XML 文档的 string。

4. initialDocument:与 DataSource 数据源的 initialData 属性类似。同样的,您应该尽可能的使

用这个属性而不是 autoLoad 属性。

5. isReady:与 DataSource 的相应属性类似。代表该数据源是否加载并解析完成了 XML 数据。

6. parameters:Web Service 的参数。

7. serviceURL:数据源请求数据的 Web Service 的 URL。您必须提供这个属性。

8. xpath:xpath 字符串,用来在从 document 属性解析 data 属性时选择解析的 path。

XMLDataSource 数据源有如下方法:

1. load:从服务器取得数据。

XMLDataSource 数据源有如下事件:

1. dataAvailable:将在成功取得数据后被引发。

博客园 @ Dflying 版权所有 11/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

B. DataColumn、DataRow 和 DataTable

在这篇文章中我们将要接触Atlas客户端数据组件中的核心组件——DataTable。顾名思义,DataTable用来表示一个表

格状的数据结构。在Atlas客户端数据组件中,DataTable对象是数据源(例如DataSource对象,请参考:Atlas命名

空间Sys.Data下控件介绍——DataSource和XMLDataSource )和数据显示控件(例如ListView控件,请

参考:使用ASP.NET Atlas ListView控件显示列表数据 )之间的桥梁。DataTable对象是DataSource对象中

的一个字段,DataSource对象从服务器取得的数据将被解析并存放在这个DataTable对象中。DataTable对象还可以被

DataView对象修饰,例如过滤并只显示其中一部分的行,按照某一列排序,分页等等,当然这些操作都是在客户端进行

的,有着极高的效率。

Atlas 的 Sys.Data 组件借用了很多大家都熟悉的 ASP.NET 和 ADO.NET 的架构。例如,Atlas 的

DataSource 类似于 ADO.NET 中的 SqlDataSource 对象,Atlas 中的 DataTable 类似于 ADO.NET 中的

DataTable 对象,Atlas 中的 ListView 类似于 ASP.NET 中的 ListView 对象。这种开发模型让我们开发人

员感到非常熟悉并更加容易上手。

DataTable 类包含一个 DataColumn 对象的集合以及一个 DataRow 对象的集合,让我们从 DataColumn

和 DataRow 对象开始:

Sys.Data.DataColumn

DataColumn 类非常简单,只有如下几个很容易理解的属性:

1. columnName:本列的名称。

2. dataType:本列中的数据类型。

3. defaultValue:本列中数据的默认值。

4. isKey:本列中是否为 DataTable 的关键字段。

5. readOnly:本列中的数据是否为只读属性。

Sys.Data.DataRow

DataRow 类略显复杂,包含如下属性:

1. $isDirty:该行是否经过修改并且尚未提交到服务器保存。

博客园 @ Dflying 版权所有 12/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

2. $index: 该行在 DataTable 中的索引值。

3. $selected:该行是否被选中。

还包含有如下事件:

1. propertyChanged:当上述的三个属性被改变时被引发。

Sys.Data.DataTable

下面轮到 DataTable 了,DataTable 类实现了 Sys.Data.IData 接口,该接口提供的方法在下面的方法


列表中,这里不单说明。

DataTable 对象有如下属性:

1. columns:取得当前 DataTable 对象中 DataColumn 对象的集合。您可以对该集合进行添加,删

除或修改等操作以修改该 DataTable 的 Schema。

2. keyNames:该 DataTable 对象中所有关键列的 columnName 属性集合。

3. length:该 DataTable 对象中 DataRow 数目。

4. isDirty:该 DataTable 对象中是否有 DataRow 被修改且尚未提交到服务器保存。

DataTable 对象有如下方法:

1. add:将传入的 DataRow 对象添加到当前的 DataTable 中。传入的 DataRow 对象必须与该

DataTable 有同样的 Schema。推荐首先使用 createRow 方法来创建新行,然后作为本方法的参

数。

2. clear:清除当前 DataTable 的所有行。

3. remove:根据传入的 DataRow 对象,删除当前 DataTable 的某一行。

4. createRow:根据当前 DataTable 的 Schema 创建一个新行。

5. getChanges:取得对该 DataTable 的修改。该方法的返回值有如下三个集合:

a. updated:修改过的 DataRow 的集合。

b. inserted:添加过的 DataRow 的集合。

c. deleted:删除过的 DataRow 的集合。

6. getColumn:根据传入的列名查找并返回该 DataTable 中的某个 DataColumn 对象。

7. getRow:根据传入的索引值返回相应的 DataRow 对象。

博客园 @ Dflying 版权所有 13/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

8. getItem:与 getRow 方法功能完全一样,估计是为了提供一个更加泛化的名称。

还有如下事件:

1. collectionChanged:当 DataTable 的行被改变后被引发。

2. propertyChanged:当以上的某个属性被改变后被引发。

C. DataView 和 DataFilter

这篇文章是Atlas命名空间Sys.Data下控件介绍这个系列的第三篇,也是最后的一篇。在我的前两篇文章(Atlas命名空

间Sys.Data下控件介绍——DataSource和XMLDataSource ,Atlas命名空间Sys.Data下控件介绍

——DataColumn,DataRow和DataTable)中,我们讨论了如何用数据源控件从服务器取得数据并保存在客户端,以

及如何用DataTable对象对客户端的数据进行操作。目前为止,我们可以直接将数据显示给用户了,但是,很多时候我

们需要在这之前对数据进行一定的修饰,例如,当DataTable中的数据量很大时,我们需要实现分页的功能,或是用户

希望根据某一列进行排序,或者用户只对数据中的某一些感兴趣(例如,name等于Dflying的条目)。这也是Atlas中引

入DataView以及DataFilter对象的目的。在这篇文章中,我将介绍如何使用DataView和DataFilter对象修饰取得的数

据,以提供给UI控件显示。

DataView 对象可以实现分页以及排序的功能,并利用 DataFilter 对数据进行过滤。下面是 DataView 对象

的属性:

1. data:储存未被修饰的原数据。您应该总是将用 DataSource 控件取得的 DataTable 对象设置给

这个属性,以备操作。

2. filteredData:经过修饰的数据,例如经过分页的数据或者经过过滤的数据。

3. filters:将要应用到 data 属性上的 DataFilter 的集合。您可以指定多个 DataFilter 对象,它们将

被依次应用于原数据上以对其进行过滤。对于 DataFilter 对象的介绍请参见下文。

4. hasNextPage:当前页后是否有下一页。

5. hasPreviousPage:当前页前是否有前一页。

6. length:当前页中实际的条目数量。

7. pageCount:当前 DataView 中的页数。

8. pageIndex:当前页的索引。

博客园 @ Dflying 版权所有 14/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

9. pageSize:每一页的长度(每一页中最多有多少个条目)。如果您需要分页功能,则应该设置这个

属性。

10. sortColumn:DataView 将依据这个属性中指定的列排序。如果您需要排序功能,则应该设置这

个属性。

11. sortDirection:排序的方向。可选 Ascending(默认)或 Descending。

DataView 对象还有下面一个方法:

1. sort:根据 sortColumn 属性和 sortDirection 属性对当前数据集合进行排序操作。

请注意,您可能需要两个位于Sys.Data.UI命名空间的控件:DataNavigator和SortBehavior,来帮助您实现分页和排

序的功能。关于DataView以及上述两个控件的介绍以及示例程序,请参考 使用 ASP.NET Atlas PageNavigator控件

实现客户端分页导航 。

DataView 的介绍就暂到这里,我们来看一下 DataFilter 对象:

DataFilter 用来提供对数据的过滤功能。Atlas 中的 Sys.Data.DataFilter 类被定义成所有 Filter 类的抽象基类。它提

供了一个抽象方法,filter。所有的派生类都要采用自己的逻辑来实现这个方法,用来提供相应的过滤规则。

Atlas 提供了一个内建的 DataFilter:PropertyFilter,它可以根据集合中条目的某个属性值来过滤这个集合。

PropertyFilter 有如下两个属性:

1. property:这个 Filter 将应用于条目的哪个属性。

2. value:期待的这个属性的值。只有该条目的这个属性的值等于这里指定的值的时候,该条目才能被

这个 Filter 过滤出来。

PropertyFilter 的示例程序将很快完成。

在这个系列的最后,让我们来总结一下 Atlas 命名空间 Sys.Data 下的这三类控件。如果您能理解这三类控

件,将对您未来的 Atlas 开发大有裨益。

博客园 @ Dflying 版权所有 15/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

1. DataSource和XMLDataSource(Atlas命名空间Sys.Data下控件介绍——DataSource和

XMLDataSource),用来从服务器端取得数据并将数据保存在客户端,同样在用户修改后可以将数

据提交回服务器保存。

2. DataTable,包括DataRow和DataColumn(Atlas命名空间Sys.Data下控件介绍

——DataColumn,DataRow和DataTable),是客户端数据的实际储存对象。通过DataTable的方

法,您可以在客户端对数据进行操作(添加,删除,修改等)

3. DataView 和 DataFilter(本文),用来在显示给用户前对数据进行修饰(分页,排序,过滤等),有

些类似于 SQL 的 where 和 order by 子句,当然这些操作都是在客户端发生的,并且不影响实际

的客户端数据,同样类似于 SQL 中视图(View)的概念。

博客园 @ Dflying 版权所有 16/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

第三章 Atlas 数据控件介绍

A. 使用 ASP.NET Atlas ListView 控件显示列表数据

在目前的大部分 Web 程序中,我们都需要显示给用户一些列表数据。ASP.NET 中的 GridView 服务器控件

提供了这种功能,Atlas 中的客户端控件 ListView 也可以在客户端提供类似功能,并以 AJAX 方式运行。虽

然您可以使用传统的 GridView 控件加上 Atlas 的 UpdatePanel 提供同样的 AJAX 运行方式,但是这种实现

方式较低效,也不是“纯粹”的 Atlas 方法。推荐的方法是采用 Atlas 的客户端控件 ListView 来代替。不要担

心,Atlas 的 ListView 控件和 GridView 一样简单,而其二者在很多概念方面是相似的,


例如 ItemTemplate。

但是需要注意的是目前 IDE 中并没有提供对 Atlas 脚本的智能感知功能,加之 Atlas 脚本也没有编译时期检

查,所以在书写代码的时候应该格外小心。

使用 ListView 的时候应该提供给其一些必要的模版(Template),以告诉 Atlas 应该如何渲染您的内容。

ListView 中有如下模版:

1. layoutTemplate:这个模版用来渲染包含列表项目的容器(例如使用<table>标记)
,列表的头

部(例如使用<thead>标记),尾部等。您必须为 ListView 指定一个 layoutTemplate。而且这个

模版必须包含一个 itemTemplate 模版,也可选包含一个 separatorTemplate 模版。

2. itemTemplate:这个模版用来渲染列表中的一个项目(例如使用<tr>标记)。这个模版必须被置

于 layoutTemplate 中。

3. separatorTemplate:这个模版用来渲染列表中的项目之间的分隔元素(例如使用<hr>标记)。

这个模版必须被置于 layoutTemplate 中。

4. emptyTemplate.:这个模版用来渲染没有项目存在时的 ListView。此时可能与该 ListView 相关

的 DataSource 对象中没有项目,或是正在从服务器中取得的过程中。

ListView 中还有一些属性:

1. itemCssClass:指定项目条目的 css class。

2. alternatingItemCssClass:指定间隔的项目条目的 css class。

3. selectedItemCssClass:指定被选中的项目条目的 css class。

4. separatorCssClass:指定分隔元素的 css class。

博客园 @ Dflying 版权所有 17/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

5. itemTemplateParentElementId:这个属性指定了 itemTemplate 和 separatorTemplate

的父元素。这样 itemTemplate 和 separatorTemplate 元素就可以在其中被重复渲染。

ListView还有一些继承于Sys.UI.Data.DataControl基类的方法/属性,因为在下面的代码中我们不需要使用,这里

暂且略过。如果您感兴趣,可以参考这篇文章:使用ASP.NET Atlas ItemView控件显示集合中的单个数据。OK,让我

们通过一个实例来说明如何使用ListView控件:

首先,我们编写一个返回.NET 中 DataTable 的 Web Service。注意到在这里将继承于

Microsoft.Web.Services.DataService 基类,并且为 service 方法加上定义在名称空间

System.ComponentModel 中的属性 DataObjectMethod。在 service 方法的开头,我们使用

System.Threading.Thread.Sleep(2000)来模拟 2 秒钟的网络延迟,以便可以看到 emptyTemplate 中

的内容。

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class MyService : Microsoft.Web.Services.DataService {

[DataObjectMethod(DataObjectMethodType.Select)]
public DataTable GetListData()
{
System.Threading.Thread.Sleep(2000);

DataTable dt = new DataTable("MyListData");


dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Email", typeof(string));
DataRow newRow;
for (int i = 0; i < 5; ++i)
{
newRow = dt.NewRow();
newRow["Name"] = string.Format("Dflying {0}", i);
newRow["Email"] = string.Format("Dflying{0}@dflying.net", i);
dt.Rows.Add(newRow);
}
return dt;
}
}
然后,添加一些 ASP.NET 页面中必须的控件/标记:

<atlas:ScriptManager ID="ScriptManager1" runat="server" />


<!-- Element for myList (container) -->

博客园 @ Dflying 版权所有 18/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

<div id="myList"></div>
<!-- Layout Elements -->
<div style="display: none;">
</div>

在上面的标记中,我们加入了三个标记:一个必须的 ScriptManager 控件。一个 id 为 myList 的 div,用来

让 Atlas 把渲染后的 ListView 放置于这里。一个隐藏的 div,用于定义我们的模版。这个隐藏 div 中的元素

在页面上是不可见的,只是用来提供给 Atlas 必要的模版。

我们在这个隐藏的 div 中加入如下 ListView 的模版:

<!-- Layout Template -->


<table id="myList_layoutTemplate" border="1" cellpadding="3">
<thead>
<tr>
<td><span>No.</span></td>
<td><span>Name</span></td>
<td><span>Email</span></td>
</tr>
</thead>
<!-- Repeat Template -->
<tbody id="myList_itemTemplateParent">
<!-- Repeat Item Template -->
<tr id="myList_itemTemplate">
<td><span id="lblIndex" /></td>
<td><span id="lblName" /></td>
<td><span id="lblEmail" /></td>
</tr>
<!-- Separator Item Template -->
<tr id="myList_separatorTemplate">
<td colspan="3">Separator</td>
</tr>
</tbody>
</table>
<!-- Empty Template -->
<div id="myList_emptyTemplate">
No Data
</div>

博客园 @ Dflying 版权所有 19/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

上面的代码中您可以看到我提到的所有四种模版。另外还要指定每一个模版一个 id,将用于下面的 Atlas 脚

本声明中。在这个例子中我将以 HTML Table 的形式渲染这个 ListView,很抱歉分隔元素将会很丑陋(一个

空行)。

最后在页面中添加 Atlas 脚本声明:

<dataSource id="listDataSource" autoLoad="true" serviceURL="MyService.asmx" />

<listView id="myList" itemTemplateParentElementId="myList_itemTemplateParent">


<bindings>
<binding dataContext="listDataSource" dataPath="data" property="data" />
</bindings>
<layoutTemplate>
<template layoutElement="myList_layoutTemplate" />
</layoutTemplate>
<itemTemplate>
<template layoutElement="myList_itemTemplate">
<label id="lblIndex">
<bindings>
<binding dataPath="$index" transform="Add" property="text"/>
</bindings>
</label>
<label id="lblName">
<bindings>
<binding dataPath="Name" property="text" />
</bindings>
</label>
<label id="lblEmail">
<bindings>
<binding dataPath="Email" property="text" />
</bindings>
</label>
</template>
</itemTemplate>
<separatorTemplate>
<template layoutElement="myList_separatorTemplate" />
</separatorTemplate>
<emptyTemplate>
<template layoutElement="myList_emptyTemplate"/>
</emptyTemplate>
</listView>

博客园 @ Dflying 版权所有 20/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

这里我添加了一个Atlas客户端DataSource对象以从Web Service中取得数据。这里我们暂且不多
谈DataSource(可能在后续文章中有所介绍)。让我们来看一下ListView相关的定义:在ListView

的定义中,我们指定了itemTemplateParentElementId属性。然后在ListView的内部定义了一个

binding段,用来把DataSource中取得的数据与这个ListView绑定起来。我们还定义了四个模版段,

每个模版段都用layoutElement与上面定义过的四种模版关联。注意到在layoutTemplate模版中的第

一个label控件,我们在其绑定中指定了一个Add transformer以将从 0 开始的顺序变为从 1 开始(关

于Atlas Transformer,请参考我的这篇文章:

http://dflying.cnblogs.com/archive/2006/04/05/367908.html)。

大功告成,运行一下吧。

装载中:

博客园 @ Dflying 版权所有 21/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

装载完成:

示例代码可以在此下载:http://www.cnblogs.com/Files/dflying/AtlasListViewDemo.zip

B. 使用 ASP.NET Atlas ItemView 控件显示集合中的单个数据

有时候我们需要显示给用户列表中某一项的详细信息,例如,在购物程序中的产品详细情况。ASP.NET Atlas

ItemView 客户端控件为您提供了对这项功能的支持,就像 ASP.NET 服务器端控件 DetailsView 一样,但

Atlas ItemView 控件完全在客户端运行。

ItemView类(ListView类同样,见 使用ASP.NET Atlas ListView控件显示列表数据 )继承于


Sys.UI.Data.DataControl基类。该基类提供了一些公共的属性,包括:

1. canMoveNext:当前记录后是否有下一条记录。

2. canMovePrevious:当前记录前是否有前一条记录。

3. data:控件包含的数据集合。

4. dataIndex:当前记录的 index。

博客园 @ Dflying 版权所有 22/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

5. dataItem:基于 dataIndex 的当前的记录。

6. length:记录的条目数。

同时还包括下列方法:

1. addItem:添加一条记录到当前的数据集合中。

2. deleteCurrentItem:删除基于 dataIndex 的当前记录。

3. moveNext:如果 canMoveNext 为 true,将 dataIndex 加 1,指向下一条记录。

4. movePrevious:如果 canMovePrevious 为 true,将 dataIndex 减 1,指向前一条记录。

请注意所有的以上操作都仅在客户端,也就是说只修改了客户端的数据。所以如果您希望将改变提交到服务

器,则需要调用 DataSource 的相应方法。

ItemView 通过继承获得了以上的属性和方法,并且还对基类有如下扩展:

1. itemTemplate:指定项目模版。Atlas 可以根据这个模版渲染您的内容。

2. emptyTemplate:指定无数据时的模版。当数据集合为空或者 DataSource 还在取得数据的过程

中时,Atlas 会显示这个模版。

以上是 ItemView 的简要介绍。让我们通过一个例子来熟悉 ItemView。这个程序基于 Atlas 官方发布的示

例程序,并适当做了一些简化。

首先暴露一个 Web Service 以被 Atlas 使用。

定义 item entry 类:

public class Entry

private string _name;

private string _description;

private int _id;

[DataObjectField(true, true)]

博客园 @ Dflying 版权所有 23/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

public int Id

get { return _id; }

set { _id = value; }

[DataObjectField(false)]

[DefaultValue("New row")]

public string Name

get { return _name; }

set { _name = value; }

[DataObjectField(false)]

[DefaultValue("")]

public string Description

get { return _description; }

set { _description = value; }

public Entry()

_id = -1;

public Entry(int id, string name, string description)

_id = id;

博客园 @ Dflying 版权所有 24/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

_name = name;

_description = description;

定义 Web Methods。我们需要提供 Select,Insert,Update 以及 Delete 方法以期对我们的数据集合进

行完整的 CRUD 操作。注意到我们在初始化数据时使用了 System.Threading.Thread.Sleep(2000)来模

拟两秒钟的网络延迟,这样可以看到 emptyTemplate 中的内容。

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

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

public class MyDataService : DataService

static List<Entry> _data;

static int _nextId;

static object _dataLock = new object();

private static List<Entry> Data

get

if (_data == null)

lock (_dataLock)

if (_data == null)

System.Threading.Thread.Sleep(2000);

_data = new List<Entry>();

_data.Add(new Entry(0, "ListView", "A control to display data using templa

博客园 @ Dflying 版权所有 25/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

tes."));

_data.Add(new Entry(1, "Window", "A control to display dialogs."));

_data.Add(new Entry(2, "Weather", "A control to display local weather."));

_nextId = 3;

return _data;

[DataObjectMethod(DataObjectMethodType.Delete)]

public void DeleteRow(int id)

foreach (Entry row in _data)

if (row.Id == id)

lock (_dataLock)

_data.Remove(row);

break;

[DataObjectMethod(DataObjectMethodType.Select)]

public Entry[] SelectRows()

博客园 @ Dflying 版权所有 26/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

return MyDataService.Data.ToArray();

[DataObjectMethod(DataObjectMethodType.Insert)]

public Entry InsertRow(string name, string description)

Entry newRow;

lock (_dataLock)

newRow = new Entry(_nextId++, name, description);

_data.Add(newRow);

return newRow;

[DataObjectMethod(DataObjectMethodType.Update)]

public void UpdateRow(Entry updateRow)

foreach (Entry row in _data)

if (row.Id == updateRow.Id)

row.Name = updateRow.Name;

row.Description = updateRow.Description;

break;

然后,在 ASP.NET 中加入必须的标记,控件以及 ItemView 的模版。我们需要添加如下五部分的脚本:

博客园 @ Dflying 版权所有 27/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

1. Atlas 服务器端控件 ScriptManager。所有的 Atlas 页面中都需要包含这个控件以装载 Atlas 所必须

的 JavaScript 文件。

2. id 为 detailsView 的<div>,将被 Atlas 用来输出渲染后的内容。

3. 导航部分,用于在在客户端集合中导航,以显示集合中不同的记录。

4. 命令部分,用于修改,添加,删除记录(在客户端),并且提交到服务器。

5. 模版部分,用于指定相应的 ItemView 模版。所有的模版将被置于一个隐藏的 div 中,这样不会在

页面上显示出来。

<!-- ScriptManager -->


<atlas:ScriptManager runat="server" ID="scriptManager" />

<!-- Element for ItemView (container) -->


<div id="detailsView">
</div>

<!-- Navigators -->


<input type="button" id="previousButton" value="<" title="Go to previous row" />
<span id="rowIndexLabel"></span>
<input id="nextButton" type="button" value=">" title="Go to next row" />
|
<!-- Commands -->
<input type="button" id="addButton" value="New" title="Create a new row" />
<input type="button" id="delButton" value="Delete" title="Delete the current row" />
|
<input type="button" id="saveButton" value="Save" title="Save all pending changes" />

<input type="button" id="refreshButton" value="Refresh" title="Discard pending changes and


get the latest data from the server" />

<!-- Templates -->


<div style="visibility: hidden; display: none">
<div id="detailsTemplate">
Name:
<input id="nameField" size="30" /><br />
Description:<br />
<textarea id="descriptionField" rows="4" cols="40"></textarea><br />
</div>
<div id="emptyTemplate">

Getting Data

</div>

博客园 @ Dflying 版权所有 28/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

</div>

最后需要做的是在页面上添加 Atlas 脚本。

下面是 DataSource 的脚本:

<dataSource id="dataSource" serviceURL="MyDataService.asmx" autoLoad="true" />


下面是 ItemView 的脚本。我们将绑定上面的 DataSource 控件作为数据源,并且将 ItemView 的 enabled

属性绑定到 DataSource 的 isReady 属性上,以期在数据源没有装载完成前禁用 ItemView。同样为

ItemView 定义了 itemTemplate 和 emptyTemplate。

<itemView id="detailsView">
<bindings>
<binding dataContext="dataSource" dataPath="data" property="data"/>
<binding dataContext="dataSource" dataPath="isReady" property="enabled"/>
</bindings>
<itemTemplate>
<template layoutElement="detailsTemplate">
<textBox id="nameField">
<bindings>
<binding dataPath="Name" property="text" direction="InOut"/>
</bindings>
</textBox>
<textBox id="descriptionField">
<bindings>
<binding dataPath="Description" property="text" direction="InOut"/>
</bindings>
</textBox>
</template>
</itemTemplate>
<emptyTemplate>
<template layoutElement="emptyTemplate" />
</emptyTemplate>
</itemView>

下面是导航部分的脚本。我们提供了一个label用来显示当前的记录编号(记录index加上 1,使用了Atlas

的Add transformer。关于Atlas transformer,您可以参考:在ASP.NET Atlas中创建自定义的

Transformer )。还提供了前后移动记录的导航按钮(通过使用Atlas的InvokeMethod action调用

相应的ItemView的方法)。

<button id="previousButton">

博客园 @ Dflying 版权所有 29/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

<bindings>
<binding dataContext="detailsView" dataPath="canMovePrevious" property="enabled"
/>
</bindings>
<click>
<invokeMethod target="detailsView" method="movePrevious" />
</click>
</button>

<label id="rowIndexLabel">
<bindings>
<binding dataContext="detailsView" dataPath="dataIndex" property="text" transfor
m="Add" />
</bindings>
</label>

<button id="nextButton">
<bindings>
<binding dataContext="detailsView" dataPath="canMoveNext" property="enabled"/>
</bindings>
<click>
<invokeMethod target="detailsView" method="moveNext" />
</click>
</button>

下面是命令部分的脚本。这里我们能够在客户端添加/删除记录,并将改变提交给服务器或者放弃提交。

<button id="addButton">
<bindings>
<binding dataContext="dataSource" dataPath="isReady" property="enabled"/>
</bindings>
<click>
<invokeMethod target="detailsView" method="addItem" />
</click>
</button>

<button id="delButton">
<bindings>
<binding dataContext="dataSource" dataPath="isReady" property="enabled"/>
</bindings>
<click>
<invokeMethod target="detailsView" method="deleteCurrentItem" />
</click>
</button>

博客园 @ Dflying 版权所有 30/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

<button id="saveButton">
<bindings>
<binding dataContext="dataSource" dataPath="isDirtyAndReady" property="enabled"/
>
</bindings>
<click>
<invokeMethod target="dataSource" method="save" />
</click>
</button>

<button id="refreshButton">
<bindings>
<binding dataContext="dataSource" dataPath="isReady" property="enabled"/>
</bindings>
<click>
<invokeMethod target="dataSource" method="load" />
</click>
</button>

大功告成,可以在浏览器中测试了。

装载中:

博客园 @ Dflying 版权所有 31/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

装载完成:

记录间导航:

博客园 @ Dflying 版权所有 32/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

修改并保存:

上述示例代码可以在此处下载:http://www.cnblogs.com/Files/dflying/AtlasItemViewDemo.zip

C. 使用 ASP.NET Atlas PageNavigator 控件实现客户端分页导航

把所有的记录统统放在一个页面上绝对不是一个好主意,特别是当您有成百上千条记录时。您的用户需

要不停的拖动滚动条,甚至使用 Control+F 来找到所期待的内容,这将带来相当差的用户体验。这时,

将数据以分页的方式显示给用户将友好的多。 一些 ASP.NET 服务器端控件拥有内建的分页及页面导航

功能,例如 DataGrid 和 GridView。同样的,Atlas 客户端控件 Sys.UI.Data.DataNavigator 也提供

了类似的功能,这将大大提高我们的开发效率。

DataNavigator控件将与DataView(请参考:Atlas命名空间Sys.Data下控件介绍——DataView和

DataFilter )控件一起工作。我们知道DataView控件没有提供页面导航相关方法,所以我们只能直接

设置它的pageIndex属性来实现导航。虽然没有什么难度,但很多情况下这并不是一个好办法,因为像

我这样好多粗心的开发者往往会忘记检查pageIndex的边界值,造成不必要的麻烦。这也是Atlas要提供

DataNavigator控件的原因之一,DataNavigator控件将作为一个DataView控件的代理(proxy),

提供易用的页面导航接口。

DataNavigator 对象只有一个属性:

博客园 @ Dflying 版权所有 33/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

1. dataView:对某个 DataView 对象的引用,这个 DataNavigator 将把页面导航的操作应用

到其上。您应该总是指定这个属性。

另外,要使用 DataNavigator 控件,您还需要提供一些拥有一些指定 commandName 属性的 Atlas Button,

以触发相应的页面导航操作。这些 Button 的 parent 属性应该设定为此 DataNavigator 控件,以保证

DataNavigator 能够捕获到这些 Button 发出的命令。

您可以指定您的 Button 的 commandName 属性为如下五个 string,每个都有不同的含义:

1. page:将当前页面索引转为命令参数(command argument)中指定的值。通过这个命令我们可

以快速的改变页面的索引。

2. nextpage:切换到下一页(如果存在下一页)。

3. previouspage:切换到上一页(如果存在上一页)

4. firstpage:切换到第一页。

5. lastpage:切换到最后一页。

OK,MSDN 般枯燥的介绍到此为止吧,让我们通过一个实例来熟悉 DataNavigator 的使用方法。

首先我们需要暴露一个 Web Service,以便 Atlas 页面使用。该 Web Service 将返回 100 条记录。下面就

是这个 Web Service 的代码,非常易于理解,这里不赘。

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Web;
using System.Web.Caching;
using System.Web.Services;
using System.Web.Services.Protocols;
using Microsoft.Web.Services;

//
// For simplicity this example demonstraes storing and manipulating
// the data objects in memory. A database can also be used.
//

博客园 @ Dflying 版权所有 34/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class MyDataService : DataService
{
static List<Entry> _data;
static object _dataLock = new object();

private static List<Entry> Data


{
get
{
if (_data == null)
{
lock (_dataLock)
{
if (_data == null)
{
_data = new List<Entry>();
for (int i = 0; i < 100; i++)
{
_data.Add(new Entry(i, "Dflying " + i.ToString(), string.Forma
t("Dflying{0}@dflying.net", i.ToString())));
}
}
}
}
return _data;
}
}

[DataObjectMethod(DataObjectMethodType.Select)]
public Entry[] SelectRows()
{
return MyDataService.Data.ToArray();
}
}

public class Entry


{
private string _name;
private string _email;
private int _id;

博客园 @ Dflying 版权所有 35/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

[DataObjectField(true, true)]
public int Id
{
get { return _id; }
set { _id = value; }
}

[DataObjectField(false)]
[DefaultValue("New row")]
public string Name
{
get { return _name; }
set { _name = value; }
}

[DataObjectField(false)]
[DefaultValue("")]
public string Email
{
get { return _email; }
set { _email = value; }
}

public Entry()
{
_id = -1;
}

public Entry(int id, string name, string description)


{
_id = id;
_name = name;
_email = description;
}
}

然后,在 ASPX 页面中我们需要考虑并定义如下四部分的内容:

1. 一个 ScriptManager 控件,用来包含页面必须的 Atlas Framework 相关脚本文件。通常情况下,

这也是每个 Atlas 页面必须包含的。

2. 一个占位(place holder)的 div(id 为 dataContents,见代码)。Atlas 将会把渲染后的分页的

ListView 放置于此。

博客园 @ Dflying 版权所有 36/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

3. 一个作为容器的 div(DataNavigator 控件),以及其中包含的一组按钮(命令按钮),用来实现页

面导航功能。

4. 一个隐藏的 div,用来放置 ListView 的模版。

下面是以上四部分内容的代码,关于ListView控件的模版,请参考我的这篇文章:使用ASP.NET Atlas

ListView控件显示列表数据

<!-- ScriptManager -->


<atlas:ScriptManager runat="server" ID="scriptManager" />

<!-- Element for paged ListView (container) -->


<div id="dataContents">
</div>

<!-- PageNavigator -->


<div id="pageNavigator">
<input type="button" id="btnFirstPage" value="&lt;&lt;" />
<input type="button" id="btnPrevPage" value="&lt;" />
<span id="lblPageNumber"></span> / <span id="lblPageCount"></span>
<input type="button" id="btnNextPage" value="&gt;" />
<input type="button" id="btnLastPage" value="&gt;&gt;" />
</div>

<!-- Templates -->


<div style="visibility: hidden; display: none">
<table id="myList_layoutTemplate" border="1" cellpadding="3" style="width:20em;">
<thead>
<tr>
<td><span>No.</span></td>
<td><span>Name</span></td>
<td><span>Email</span></td>
</tr>
</thead>
<!-- Repeat Template -->
<tbody id="myList_itemTemplateParent">
<!-- Repeat Item Template -->
<tr id="myList_itemTemplate">
<td><span id="lblIndex" /></td>
<td><span id="lblName" /></td>
<td><span id="lblEmail" /></td>
</tr>
</tbody>

博客园 @ Dflying 版权所有 37/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

</table>
<!-- Empty Template -->
<div id="myList_emptyTemplate">
No Data
</div>
</div>

最后该书写 Atlas 的 XML 脚本定义了,有如下五个部分:

第一部分:Atlas 客户端控件 DataSource,用来从我们上面定义的 Web Service 中取得数据。

<dataSource id="dataSource" autoLoad="true" serviceURL="MyDataService.asmx" />

第二部分:一个DataView控件(请参考:Atlas命名空间Sys.Data下控件介绍——DataView和

DataFilter ),用来将第一部分中取得的那 100 条数据分页。

<dataView id="view" pageSize="12">


<bindings>
<binding dataContext="dataSource" dataPath="data" property="data" />
</bindings>
</dataView>

第三部分:一个ListView控件(请参考: 使用ASP.NET Atlas ListView控件显示列表数据 ) , 用于

显示分页好的数据。

<listView id="dataContents" itemTemplateParentElementId="myList_itemTemplateParent" >


<bindings>
<binding dataContext="view" dataPath="filteredData" property="data"/>
</bindings>
<layoutTemplate>
<template layoutElement="myList_layoutTemplate"/>
</layoutTemplate>
<itemTemplate>
<template layoutElement="myList_itemTemplate">
<label id="lblIndex">
<bindings>
<binding dataPath="$index" transform="Add" property="text"/>
</bindings>
</label>
<label id="lblName">
<bindings>
<binding dataPath="Name" property="text"/>

博客园 @ Dflying 版权所有 38/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

</bindings>
</label>
<label id="lblEmail">
<bindings>
<binding dataPath="Email" property="text"/>
</bindings>
</label>
</template>
</itemTemplate>
<emptyTemplate>
<template layoutElement="myList_emptyTemplate"/>
</emptyTemplate>
</listView>

第四部分: DataNavigator 控件以及命令按钮。注意到这里我们有四个按钮,每一个都有不同的

commandName 属性,也分别对应着 DataNavigator 对 DataView 的一种操作。同时这些按钮的 parent


属性都设置成了这个 DataNavigator 对象。

<dataNavigator id="pageNavigator" dataView="view"/>


<button id="btnFirstPage" parent="pageNavigator" command="FirstPage" />
<button id="btnPrevPage" parent="pageNavigator" command="PreviousPage">
<bindings>
<binding property="enabled" dataPath="hasPreviousPage"/>
</bindings>
</button>
<button id="btnNextPage" parent="pageNavigator" command="NextPage">
<bindings>
<binding property="enabled" dataPath="hasNextPage"/>
</bindings>
</button>
<button id="btnLastPage" parent="pageNavigator" command="LastPage" />

第五部分:两个 Label,分别显示页面总数以及当前页的序号。

<label id="lblPageNumber">
<bindings>
<binding dataContext="view" property="text" dataPath="pageIndex" transform="Add"/>
</bindings>
</label>
<label id="lblPageCount">
<bindings>
<binding dataContext="view" property="text" dataPath="pageCount"/>
</bindings>

博客园 @ Dflying 版权所有 39/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

</label>

OK,在浏览器中测试一下:

这个DEMO的源文件可以在此下载:
http://www.cnblogs.com/Files/dflying/DataNavigatorDemo.zip

博客园 @ Dflying 版权所有 40/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

D. 使用 ASP.NET Atlas SortBehavior 实现客户端排序

为您的列表添加排序功能将是非常酷的。一些ASP.NET服务器控件,例如DataGrid,GridView
等已经拥有了内建的排序功能。Atlas同样提供了Sys.UI.Data.SortBehavior Behavior(有关Atlas

Behavior,请参考:在ASP.NET Atlas中创建自定义的Behavior),让您在客户端即可实现排序功能。

SortBehavior将与DataView控件(请参考:Atlas命名空间Sys.Data下控件介绍——DataView和

DataFilter)配合工作,它将通过设定DataView控件的sortDirection属性来实现排序功能。

SortBehavior对象有如下属性:

1. dataView:对某个 DataView 对象的引用,这个 SortBehavior 将把页面的排序操作应用到其上。

您应该总是指定这个属性。

2. sortColumn:DataView 中某一列的列名,SortBehavior 将根据这个列中的内容来进行排序。

您应该总是指定这个属性。

3. sortAscendingCssClass:触发排序的控件的 CSS Class(升序时)。

4. sortDescendingCssClass:触发排序的控件的 CSS Class(降序时)。

介绍到此为止,我们来看如下的示例程序。

首先我们需要暴露一个 Web Service 以便 Atlas 页面使用。该 Web Service 将返回 5 个名人(除了我)的

简介。下面为代码:

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Web;
using System.Web.Caching;
using System.Web.Services;
using System.Web.Services.Protocols;
using Microsoft.Web.Services;

//
// For simplicity this example demonstraes storing and manipulating
// the data objects in memory. A database can also be used.

博客园 @ Dflying 版权所有 41/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

//

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class SampleDataService : DataService
{
static List<Entry> _data;
static int _nextId;
static object _dataLock = new object();

private static List<Entry> Data


{
get
{
if (_data == null)
{
lock (_dataLock)
{
if (_data == null)
{
_data = new List<Entry>();
_data.Add(new Entry(0, "Dflying Chen", "A small piece of cake"));
_data.Add(new Entry(1, "Bill Gates", "Chairman & Chief Software Ar
chitect"));
_data.Add(new Entry(2, "Scott Guthrie", "General Manager"));
_data.Add(new Entry(3, "Ray Ozzie", "CTO"));
_data.Add(new Entry(4, "Steve Ballmer", "CEO"));
_nextId = 3;
}
}
}
return _data;
}
}

[DataObjectMethod(DataObjectMethodType.Delete)]
public void DeleteRow(int id)
{
foreach (Entry row in _data)
{
if (row.Id == id)
{
lock (_dataLock)
{

博客园 @ Dflying 版权所有 42/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

_data.Remove(row);
}
break;
}
}
}

[DataObjectMethod(DataObjectMethodType.Select)]
public Entry[] SelectRows()
{
return SampleDataService.Data.ToArray();
}

[DataObjectMethod(DataObjectMethodType.Insert)]
public Entry InsertRow(string name, string description)
{
Entry newRow;
lock (_dataLock)
{
newRow = new Entry(_nextId++, name, description);
_data.Add(newRow);
}
return newRow;
}

[DataObjectMethod(DataObjectMethodType.Update)]
public void UpdateRow(Entry updateRow)
{
foreach (Entry row in _data)
{
if (row.Id == updateRow.Id)
{
row.Name = updateRow.Name;
row.Title = updateRow.Title;
break;
}
}
}
}

public class Entry


{
private string _name;
private string _title;

博客园 @ Dflying 版权所有 43/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

private int _id;

[DataObjectField(true, true)]
public int Id
{
get { return _id; }
set { _id = value; }
}

[DataObjectField(false)]
[DefaultValue("New row")]
public string Name
{
get { return _name; }
set { _name = value; }
}

[DataObjectField(false)]
[DefaultValue("")]
public string Title
{
get { return _title; }
set { _title = value; }
}

public Entry()
{
_id = -1;
}

public Entry(int id, string name, string description)


{
_id = id;
_name = name;
_title = description;
}
}

然后,在 ASPX 页面中,我们需要考虑并定义如下三部分的内容:

1. 一个 ScriptManager 控件,用来包含页面必须的 Atlas Framework 相关脚本文件。通常情况下,

这也是每个 Atlas 页面必须包含的。

博客园 @ Dflying 版权所有 44/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

2. 一个占位(place holder)的 div(id 为 dataContents,见代码)


。Atlas 将会把渲染后的 ListView

放置于此。

3. 一个隐藏的 div,用来放置 ListView 的模版。

下面是以上三部分内容的代码,关于ListView控件的模版,请参考我的这篇文章:使用ASP.NET
Atlas ListView控件显示列表数据

<!-- ScriptManager -->


<atlas:ScriptManager runat="server" ID="scriptManager" />

<!-- Element for ListView (container) -->


<div id="dataContents">
</div>

<!-- Templates -->


<div style="visibility: hidden; display: none">
<div id="masterTemplate">
<table border="1" cellpadding="3" style="width:30em;">
<thead>
<tr>
<td><a href="#" id="sortId">ID</a></td>
<td><a href="#" id="sortName">Name</a></td>
<td><a href="#" id="sortTitle">Title</a></td>
</tr>
</thead>
<tbody id="masterItemTemplateParent">
<tr id="masterItemTemplate">
<td><span id="masterId"></span></td>
<td><span id="masterName"></span></td>
<td><span id="masterTitle"></span></td>
</tr>
</tbody>
</table>
</div>
</div>

最后该书写 Atlas 的 XML 脚本定义了,有如下四个部分:

第一部分:Atlas 客户端控件 DataSource,用来从我们上面定义的 Web Service 中取得数据。

<dataSource id="dataSource" autoLoad="true" serviceURL="SampleDataService.asmx" />

博客园 @ Dflying 版权所有 45/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

第二部分:一个DataView控件(请参考:Atlas命名空间Sys.Data下控件介绍——DataView和

DataFilter ),用来将第一部分中取得的数据排序。

<dataView id="view">
<bindings>
<binding dataContext="dataSource" dataPath="data" property="data"/>
</bindings>
</dataView>

第三部分:一个ListView控件(请参考: 使用ASP.NET Atlas ListView控件显示列表数据 ) , 用于

显示排序后的数据。

<listView id="dataContents" itemTemplateParentElementId="masterItemTemplateParent" >


<bindings>
<binding dataContext="view" dataPath="filteredData" property="data"/>
</bindings>
<layoutTemplate>
<template layoutElement="masterTemplate"/>
</layoutTemplate>
<itemTemplate>
<template layoutElement="masterItemTemplate">
<label id="masterId">
<bindings>
<binding dataPath="Id" property="text"/>
</bindings>
</label>
<label id="masterName">
<bindings>
<binding dataPath="Name" property="text"/>
</bindings>
</label>
<label id="masterTitle">
<bindings>
<binding dataPath="Title" property="text"/>
</bindings>
</label>
</template>
</itemTemplate>
</listView>

第四部分:三个包含 SortBehavior behavior 的 Atlas 控件,用来触发排序的操作。

博客园 @ Dflying 版权所有 46/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

<control id="sortId">
<behaviors>
<sortBehavior dataView="view" sortColumn="Id"/>
</behaviors>
</control>
<control id="sortName">
<behaviors>
<sortBehavior dataView="view" sortColumn="Name"/>
</behaviors>
</control>
<control id="sortTitle">
<behaviors>
<sortBehavior dataView="view" sortColumn="Title"/>
</behaviors>
</control>

大功告成,打开浏览器测试一下吧:

初始的顺序:

点击 Name,按照 Name 排序——升序:

博客园 @ Dflying 版权所有 47/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

再次点击 Name, 按照 Name 排序——降序:

博客园 @ Dflying 版权所有 48/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

这个DEMO的源文件可以在此下载:
http://www.cnblogs.com/Files/dflying/SortBehaviorDemo.zip

E. 使用 ASP.NET Atlas XSLTView 控件用 XSLT 修饰并显示 XML 数据

XSLT是一种修饰XML显示的样式语言,它可以将XML文件中的数据添加修饰(样式,布局等)后输出,
我们熟悉的CSDN论坛中的帖子就采用了XSLT的修饰。更多的XSLT信息,请访问W3C的XSLT标准:

http://www.w3.org/TR/xslt。

Atlas中提供了XMLDataSource控件(请参考:Atlas命名空间Sys.Data下控件介绍——DataSource和

XMLDataSource)和XSLTView控件,您可以使用他们从服务器取得XML以及XSLT数据,将XSLT样

式应用到XML数据中并显示给用户。这是个很有用的功能,例如,您可以在编写在线RSS Feed阅读程序

中使用它。

XSLTView 控件有如下几个属性:

1. document:存放 XML 数据的 XML document 对象。您可以使用 Atlas 客户端控件

XMLDataSource 从服务器获取 XML 数据。您应该总是设定这个属性。

2. transform:存放 XSLT 数据的 XML document 对象。您同样可以使用 XMLDataSource 从服务

器获取 XSLT 的数据。您应该总是设定这个属性。

3. parameters:XSLT文件中定义的parameter,将用于渲染的过程。本属性为只读。关于XSLT中

的parameter,请参考:http://www.w3schools.com/xsl/el_param.asp

还有如下方法:

1. update:用 XSLT 渲染 XML 数据。这个方法将在 XSLTView 对象初始化时或以上属性改变时被自

动调用。当然您可以在需要时手动调用。

OK,我们看一下下面的关于 XSLTView 控件和 XMLDataSource 控件的例子。

第一步是取得一些测试的数据,包含一个XML文件和一个XSLT文件。Google了一下,很容易在
http://www.w3schools.com/xsl/xsl_client.asp中找到了一个简单的。在这个示例程序中,为

博客园 @ Dflying 版权所有 49/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

简单起见,我就使用了原始的XML和XSLT文件。当然在实际的开发中,这两段数据都可以通过Web
Service或者别的CGI动态生成。

下面是 XML 文件,将其存为 MyData.xml。

<?xml version="1.0" encoding="iso-8859-1"?>


<catalog>
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
</cd>
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
</cd>
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
</cd>
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
</cd>
</catalog>

下面是 XSLT 文件,将其存为 MyStyle.xsl。

博客园 @ Dflying 版权所有 50/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

<?xml version="1.0" encoding="iso-8859-1"?>


<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<h2>My CD Collection</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th align="left">Title</th>
<th align="left">Artist</th>
</tr>
<xsl:for-each select="catalog/cd">
<tr>
<td>
<xsl:value-of select="title" />
</td>
<td>
<xsl:value-of select="artist" />
</td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>

下面我们来定义 ASPX 页面,有如下两个部分:

1. Atlas 服务器端控件 ScriptManager。所有的 Atlas 页面中都需要包含这个控件以装载 Atlas 所必须

的 JavaScript 文件。

2. id 为 dataContent 的<div>,将被 Atlas 用来输出渲染后的内容。

<!-- ScriptManager -->


<atlas:ScriptManager runat="server" ID="scriptManager" />

<!-- XSLTView here (container) -->


<div id="dataContent">
</div>

最后需要做的是在页面上添加 Atlas 脚本定义。有如下三个部分:

博客园 @ Dflying 版权所有 51/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

第一部分:一个 XMLDataSource,用来从服务器取得 XML 数据。

<xmlDataSource id="dataSource" autoLoad="true" serviceURL="MyData.xml" />

第二部分:另一个 XMLDataSource,用来从服务器取得 XSLT 数据。

<xmlDataSource id="xsltSource" autoLoad="true" serviceURL="MyStyle.xsl" />

第三部分:一个XSLTView控件,将XML数据用XSLT中的定义渲染后输出。注意到这里我们使用

binding(关于binding,请参考:Atlas揭秘 —— 绑定(Binding))来设置这个XSLTView的document

和transform属性。

<xsltView id="dataContent">
<bindings>
<binding property="document" dataContext="dataSource" dataPath="document" />
<binding property="transform" dataContext="xsltSource" dataPath="document" />
</bindings>
</xsltView>

浏览器中运行:

上述示例代码可以在此处下载:
http://www.cnblogs.com/Files/dflying/AtlasXSLTViewDemo.zip

博客园 @ Dflying 版权所有 52/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

博客园 @ Dflying 版权所有 53/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

第四章 Atlas 实战篇

A. 显示真实进度的 ProgressBar(进度条)控件

当后台在进行某些长时间的操作时,如果能在页面上提供一个显示真实进度的进度条,而
不是让用户不知情的等待或是从前的那些简单的估计,将是一个非常难得的出彩之处。现
在使用ASP.NET Atlas完全有可能做到这些。这篇文章将讨论如何完成这一功能并介绍一些有关Atlas
客户端控件开发的基本概念。您同时可以 在这里下载示例程序以及源文件。

实现网页上的进度条想法其实很简单:编写一个客户端的 Atlas 控件,每隔一段时间请求一次服务器,并使

用返回的当前进度数据更新进度条的显示。在这个示例中,将有四个部分的代码组成:

1. 一个需要较长时间才能完成的 Web Service

2. 一个用来查询上述 Web Service 进度的 Web Service

3. 客户端 Atlas 进度条(ProgressBar)控件,负责维护客户端逻辑并输出可视化 UI。这也是本示例

中最重要的一个组件,在将来可被重用于其他页面或程序的开发

4. 包含上述 Web Service 以及控件的 ASP.NET 测试页面

下面我们一步一步地来实现以上四个步骤:

需要较长时间完成的 Web Service

在实际的程序中,一个需要较长时间完成的 Web Service 可能有如下声明:

1 [WebMethod]
2 public void TimeConsumingTask()
3 {
4 ConnectToDataBase();
5 GetSomeValueFromDataBase();
6 CopySomeFilesFromDisk();
7 GetARemoteFile();
8 }

博客园 @ Dflying 版权所有 54/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

这样我们就可以插入一些辅助方法来确定当前进度完成情况,setProgress(int)用来设定当前的进度完成百

分比:

1 [WebMethod]
2 public void TimeConsumingTask()
3 {
4 setProgress(0);
5 ConnectToDataBase();
6 setProgress(10);
7 GetSomeValueFromDataBase();
8 setProgress(40);
9 CopySomeFilesFromDisk();
10 setProgress(50);
11 GetARemoteFile();
12 setProgress(100);
13 }

在本示例中,我们仅仅使用 Cache 来储存进度完成信息并利用 Thread.Sleep()方法模拟操作的延迟:

1 [WebMethod]
2 public int StartTimeConsumingTask()
3 {
4 string processKey = this.Context.Request.UserHostAddress;
5 string threadLockKey = "thread" + this.Context.Request.UserHostAddress;
6 object threadLock = this.Context.Cache[threadLockKey];
7 if (threadLock == null)
8 {
9 threadLock = new object();
10 this.Context.Cache[threadLockKey] = threadLock;
11 }
12
13 // Only allow 1 running task per user.
14 if (!Monitor.TryEnter(threadLock, 0))
15 return -1;
16
17 DateTime startTime = DateTime.Now;
18
19 // Simulate a time-consuming task.
20 for (int i = 1; i <= 100; i++)
21 {
22 // Update the progress for this task.
23 this.Context.Cache[processKey] = i;
24 Thread.Sleep(70);

博客园 @ Dflying 版权所有 55/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

25 }
26
27 Monitor.Exit(threadLock);
28
29 return (DateTime.Now - startTime).Seconds;
30 }
31

查询进度的 Web Service

很容易实现,只需从 Cache 中取得进度信息:

1 [WebMethod]
2 public int GetProgress()
3 {
4 string processKey = this.Context.Request.UserHostAddress;
5 object progress = this.Context.Cache[processKey];
6 if (progress != null)
7 {
8 return (int)progress;
9 }
10
11 return 0;
12 }

客户端进度条(ProgressBar)控件

第一步:从 Sys.UI.Control 继承

ProgressBar 控件应该继承自 Atlas 的控件基类 Sys.UI.Control,并且声明为密封类(sealed class,不

能再被继承)。Sys.UI.Control 基类包含了一些所有的控件共有的操作与方法。比如,将自己与某个 HTML

元素关联起来(也就是所谓的 binding)等。同时也要注册以让 Atlas 了解这个新的类型以便今后的声明及

使用,例如,让 Atlas 可以取得这个类型的描述等。

1 Sys.UI.ProgressBar = function(associatedElement) {
2 Sys.UI.ProgressBar.initializeBase(this, [associatedElement]);

博客园 @ Dflying 版权所有 56/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

3
4 }
5 Type.registerSealedClass('Sys.UI.ProgressBar', Sys.UI.Control);
6 Sys.TypeDescriptor.addType('script','progressBar', Sys.UI.ProgressBar);
7

第二步:添加私有成员并书写相应的 Setter/Getter

下面需要添加一些属性用来设定我们的控件。在这个例子中,我们需要三个属性:

1. Interval. 每次重新查询进度并更新进度条的间隔时间。单位:毫秒

2. Service Url. Web Service 文件的路径。

3. Service Method. 取得进度信息的方法名。

这些属性应该严格遵守 Atlas 的命名规范:Getter 应该以'get_'开头,Setter 应该以'set_'开头并传入一个

参数。还需要在控件的描述方法(descriptor)中添加对于这些属性的说明。有关描述方法(descriptor)

将在第四步中说明。例如,针对 Service Method 属性,我们有如下声明:

1 var _serviceMethod;
2
3 this.get_serviceMethod = function() {
4 return _serviceMethod;
5 }
6
7 this.set_serviceMethod = function(value) {
8 _serviceMethod = value;
9 }

第三步:使用 Timer 控件每隔一段时间查询一次 Web Service

Sys.Timer 用于每过一段时间调用一个方法(发出一个事件),我们可以定义一个委托来指向这个方法,并

在并在每一个时间段内查询这个 Web Service。为了避免浏览器内存泄露,在控件析构(dispose)的时候

应该记得做一些必要的清理。

博客园 @ Dflying 版权所有 57/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

还有,注意当前一个请求并没有返回时,不应该发送第二个请求。

1 var _timer = new Sys.Timer();


2 var _responsePending;
3 var _tickHandler;
4 var _obj = this;
5
6 this.initialize = function() {
7 Sys.UI.ProgressBar.callBaseMethod(this, 'initialize');
8 _tickHandler = Function.createDelegate(this, this._onTimerTick);
9 _timer.tick.add(_tickHandler);
10 this.set_progress(0);
11 }
12
13 this.dispose = function() {
14 if (_timer) {
15 _timer.tick.remove(_tickHandler);
16 _tickHandler = null;
17 _timer.dispose();
18 }
19 _timer = null;
20 associatedElement = null;
21 _obj = null;
22
23 Sys.UI.ProgressBar.callBaseMethod(this, 'dispose');
24 }
25
26 this._onTimerTick = function(sender, eventArgs) {
27 if (!_responsePending) {
28 _responsePending = true;
29
30 // Asynchronously call the service method.
31 Sys.Net.ServiceMethod.invoke(_serviceURL, _serviceMethod, null, null, _onMetho
dComplete);
32 }
33 }
34
35 function _onMethodComplete(result) {
36 // Update the progress bar.
37 _obj.set_progress(result);
38 _responsePending = false;
39 }

博客园 @ Dflying 版权所有 58/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

第四步:添加控制方法

我们应该可以控制进度条的开始/停止。并且,对于一个 Atlas 控件,相关的描述方法(descriptor)也是必

须的。Atlas 会利用它来描述这个类型的信息。

1 this.getDescriptor = function() {
2 var td = Sys.UI.ProgressBar.callBaseMethod(this, 'getDescriptor');
3 td.addProperty('interval', Number);
4 td.addProperty('progress', Number);
5 td.addProperty('serviceURL', String);
6 td.addProperty('serviceMethod', String);
7 td.addMethod('start');
8 td.addMethod('stop');
9 return td;
10 }
11
12 this.start = function() {
13 _timer.set_enabled(true);
14 }
15
16 this.stop = function() {
17 _timer.set_enabled(false);
18 }

OK,目前为止客户端的控件就完成了。我们把它存为 ProgressBar.js。

ASP.NET Testing Page ASP.NET 测试页面

对于任何的 Atlas 页面,我们第一件需要做的事情就是添加一个 ScriptManager 服务器控件。在这个示例中

我们将引用 ProgressBar 控件,较长时间才能完成的 Web Service 以及进度查询 Web Service。(这两

个 Web Service 位于同一个文件中:TaskService.asmx)

1 <atlas:ScriptManager ID="ScriptManager1" runat="server" >


2 <Scripts>
3 <atlas:ScriptReference Path="ScriptLibrary/ProgressBar.js" ScriptName="Custom"
/>
4 </Scripts>
5 <Services>

博客园 @ Dflying 版权所有 59/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

6 <atlas:ServiceReference Path="TaskService.asmx" />


7 </Services>
8 </atlas:ScriptManager>

接下来是页面的布局与样式:

1 <style type="text/css">
2 * {
3 font-family: tahoma;
4 }
5 .progressBarContainer {
6 border: 1px solid #000;
7 width: 500px;
8 height: 15px;
9 }
10 .progressBar {
11 background-color: green;
12 height: 15px;
13 width: 0px;
14 font-weight: bold;
15 }
16 </style>
17
18 <div>Task Progress</div>
19 <div class="progressBarContainer">
20 <div id="pb" class="progressBar"></div>
21 </div>
22
<input type="button" id="start" onclick="startTask();return false;" value="Start the Time
Consuming Task!" />
23 <div id="output" ></div>

最后是一段 JavaScript 启动那个较长时间才能完成的 Web Service 并让 ProgressBar 控件开始工作:

截图和下载

现在所有的事情都搞定了,可以运行了!

博客园 @ Dflying 版权所有 60/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

页面初始化:

运行中:

博客园 @ Dflying 版权所有 61/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

运行完成:

示例程序以及源文件可以 在这里下载。

B. 创建自定义的 Action

Action 是 ASP.NET Atlas 中继承于 Sys.Action 基类的的一类组件,用来实现一类由某个事件引发


的事件处理功能。Action 与事件处理函数的功能类似,但它是一类泛化了的事件处理组件,用来描述一

些常见的,通用的事件处理方法,例如调用某个方法,设定某个对象的某个属性,引发一个 PostBack

等。

我们都知道,目前为止,Atlas 最好的参考手册就是它的源代码。我们可以从源代码中找到如下三种 Atlas

的内建 Action,他们都继承于 Sys.Action 基类:

1. Sys.InvokeMethodAction:用来调用一个指定的函数。

2. Set.SetPropertyAction:用来设定某个对象的某个属性值。

3. Sys.WebForms.PostBackAction:用来引发一个 PostBack。

在实际的项目中,仅仅使用以上三个内建的 Action 往往是不够的,我们通常会需要自己定义一些


在项目中常用的 Action。幸运的是,在 Atlas 完备的架构中,创建自定义的 Action 将是非常简单的事

博客园 @ Dflying 版权所有 62/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

情。下面让我们通过一个简单的 AlertAction 示例来熟悉自定义 Action 的方法。当某个指定的事件

被引发时,AlertAction 将显示给用户一个 JavaScript 提示对话框,内含指定的文字。

通常的,创建自定义的 Action 有如下四个步骤:

1. 继承于 Sys.Action 基类。

2. 定义您的 Action 类的属性。在 AlertAction 的示例中,我们需要指定一个 message 属性用来保存

将要显示给用户的内容。

3. 实现 performAction()方法,以执行您需要的自定义操作。这个方法将被 Action 基类自动调用。在

我们的示例中,只是简单的使用 JavaScript 中的内建 alert()函数来弹出对话框,并显示 message

属性中的内容。

4. 为您的自定义 Action 在 getDescriptor()方法中添加相关的类型说明。

下面是 AlertAction 的 JavaScript 代码。上述四个步骤在代码内以注释的形式标出。将下面的代码保存为

AlertAction.js。

Sys.AlertAction = function() {
Sys.AlertAction.initializeBase(this);

// step 2
var _message;

this.get_message = function() {
return _message;
}
this.set_message = function(value) {
_message = value;
}

// step 4
this.getDescriptor = function() {
var td = Sys.AlertAction.callBaseMethod(this, 'getDescriptor');

td.addProperty('message', String);
return td;
}

// step 3
this.performAction = function() {

博客园 @ Dflying 版权所有 63/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

alert(_message);
return null;
}
}
// step 1
Sys.AlertAction.registerSealedClass('Sys.AlertAction', Sys.Action);
Sys.TypeDescriptor.addType('script', 'alertAction', Sys.AlertAction);

让我们在页面中测试一下这个 AlertAction。这里需要在页面上添加的仅仅是一个 Button,用来引发我们的

AlertAction。下面是 ASPX 文件中的 HTML 定义。不要忘记在 ScriptManager 中添加对 AlertAction.js

文件的引用。

<atlas:ScriptManager EnablePartialRendering="true" ID="ScriptManager1" runat="server">


<Scripts>
<atlas:ScriptReference Path="AlertAction.js" />
</Scripts>
</atlas:ScriptManager>
<div>
<input id="myButton" type="button" value="Click Me!" />
</div>

下面是 Atlas 脚本定义,十分简单,这里不再赘述。

<script type="text/xml-script">
<page xmlns:script="http://schemas.microsoft.com/xml-script/2005">
<components>
<button id="myButton">
<click>
<alertAction message="Button Clicked!" />
</click>
</button>
</components>
</page>
</script>

博客园 @ Dflying 版权所有 64/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

浏览器中的运行结果:

上述示例程序可以在此下载:http://www.cnblogs.com/Files/dflying/AtlasActionDemo.zip

C. 创建自定义的 Behavior

Atlas 中的 Behavior 定义了当控件的某个事件被触发时的行为。Behavior 可以看作是一种封装了的


DHTML 的事件,例如 click 和 hover 等。Behavior 同样可以是一个组件,可被 attach 到某个 Atlas

客户端控件上,以提供这个 Atlas 客户端控件更高级,更丰富的功能,例如一些复杂的拖放(drag &

drop),自动完成,浮动等功能。Behavior 将被定义在某个 Atlas 控件的 behaviors 集合中。

从 Atlas 文档以及源文件中,我们可以知道 Atlas 有如下一些内建的 Behavior:

1. Click Behavior:提供对鼠标点击的处理。

2. Floating Behavior:提供拖放(drag & drop)的效果。

3. Hover Behavior:提供对 DHTML 的事件 onmouseover,onmouseout,onfocus 以及 onblur

的处理。

4. Pop-up Component:提供 pop-up 的功能,可以用来实现高级的 tooltip。

博客园 @ Dflying 版权所有 65/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

5. Auto-complete Behavior:提供自动完成的功能。这也是 Atlas 演示中常用的功能之一。这个

Behavior 还需要服务器端的处理程序。

Click Behavior 用来处理 DHTML 的 onclick 事件,非常有用但是它提供的功能有些简单。在一些比较复杂

的程序中,我们可能需要将左右键的功能分开,例如,左键用来选择,右键用来弹出快捷菜单。虽然我们可

以把这个 if-else 放在 Click Behavior 的处理函数中,但这并不是好的 Atlas 的方法。因此,今天我们来编

写一个更加强大的 Click Behavior,叫做 ExtendedClickBehavior,它可以在 Behavior 的内部就把左右

键分开,并且引发出两个不同的事件。通过编写这个 ExtendedClickBehavior,您也可以了解在 Atlas 中创

建自定义的 Behavior 的一般过程。

通常的,创建自定义的 Behavior 有如下 5 个步骤:

1. 继承于 Sys.UI.Behavior 基类。

2. 定义您自己的事件以封装 DHTML 中的事件。这些事件将被用来暴露给其他的 Atlas 控件以代替原有

的,未经修饰的 DHTML 事件。

3. 在 Behavior 的构造函数中为您的事件指定处理函数,并在析构函数中 detach 事件的处理函数。

4. 在处理函数中发出相应的事件。在 ExtendedClickBehavior 的例子中,我们根据鼠标按键的不同来

发出不同的事件。

5. 在 getDescriptor()方法中加上对您定义的事件的描述。

下面是 ExtendedClickBehavior 的 JavaScript 代码。上述五个步骤在代码内以注释的形式标出。将下面的

代码保存为 ExtendedClickBehavior.js。

Sys.UI.ExtendedClickBehavior = function() {
Sys.UI.ExtendedClickBehavior.initializeBase(this);

var _clickHandler;

// step 2
this.click = this.createEvent();
this.leftClick = this.createEvent();
this.rightClick = this.createEvent();

this.dispose = function() {
// step 3
this.control.element.detachEvent('onmousedown', _clickHandler);

博客园 @ Dflying 版权所有 66/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

Sys.UI.ExtendedClickBehavior.callBaseMethod(this, 'dispose');
}

this.initialize = function() {
Sys.UI.ExtendedClickBehavior.callBaseMethod(this, 'initialize');

// step 3
_clickHandler = Function.createDelegate(this, clickHandler);
this.control.element.attachEvent('onmousedown', _clickHandler);
}

this.getDescriptor = function() {
var td = Sys.UI.ExtendedClickBehavior.callBaseMethod(this, 'getDescriptor');

// step 5
td.addEvent('click', true);
td.addEvent('leftClick', true);
td.addEvent('rightClick', true);
return td;
}

// step 4
function clickHandler() {
this.click.invoke(this, Sys.EventArgs.Empty);
if (window.event.button == 1)
{
this.leftClick.invoke(this, Sys.EventArgs.Empty);
}
else if (window.event.button == 2)
{
this.rightClick.invoke(this, Sys.EventArgs.Empty);
}
}
}
// step 1

Sys.UI.ExtendedClickBehavior.registerSealedClass('Sys.UI.ExtendedClickBehavior', Sys.UI.Be
havior);

Sys.TypeDescriptor.addType('script', 'extendedClickBehavior', Sys.UI.ExtendedClickBehavior


);

博客园 @ Dflying 版权所有 67/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

让我们在页面中测试一下这个 ExtendedClickBehavior。在页面上添加一个<div>用来点击,一个 label

用来显示点击的信息。下面是 ASPX 文件中的 HTML 定义。不要忘记在 ScriptManager 中添加对

ExtendedClickBehavior.js 文件的引用。

<atlas:ScriptManager EnablePartialRendering="true" ID="ScriptManager1" runat="server">


<Scripts>
<atlas:ScriptReference Path="ExtendedClickBehavior.js" />
</Scripts>
</atlas:ScriptManager>
<div>
<div id="myButton" style="border: 1px solid black; width: 20em; white-space:normal">
Click On Me (Left and Right)!</div> <br />
<span id="myLabel">not clicked</span>
</div>

下面是 Atlas 脚本定义。注意到我们使用了 Atlas 的 setProperty Action(有关 Atlas Action,请见后续文

章)用来在每次点击后设置 label 的 text。

<page xmlns:script="http://schemas.microsoft.com/xml-script/2005">
<components>
<label id="myButton">
<behaviors>
<extendedClickBehavior>
<click>
<setProperty target="myLabel" property="text" value="clicked" />
</click>
<leftClick>
<setProperty target="myLabel" property="text" value="left clicke
d" />
</leftClick>
<rightClick>
<setProperty target="myLabel" property="text" value="right click
ed" />
</rightClick>
</extendedClickBehavior>
</behaviors>
</label>
<label id="myLabel" />
</components>
</page>

浏览器中的运行结果:

博客园 @ Dflying 版权所有 68/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

没有点击:

左键点击:

博客园 @ Dflying 版权所有 69/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

右键点击:

上述示例程序可以在此下载:
http://www.cnblogs.com/Files/dflying/ExtendedClickBehaviorDemo.zip

D. 创建自定义的 Transformer

ASP.NET Atlas中的绑定(binding)是一种将两个对象连接起来的强大方法。(您可以参考
http://dflying.cnblogs.com/archive/2006/04/04/366900.html得到更多关于绑定的信息。)

Atlas绑定会自动将源对象上变化了的属性应用到目标对象的指定属性上。但有时候您会希望在应用到目

标对象之前对这个属性进行一些修改。比如,当显示一个有索引的列表时,您可能希望这个索引从 1 开

始递增,而不是JavaScript中默认的从 0 开始。这时候您就需要使用Atlas Transformer了。Atlas中

的Transformer是一种类似管道的东西,它将插入到由源对象的属性向目标对象的属性赋值的过程中,

以期对将要赋值的属性进行必要的过滤/装饰/转换(在这里是将源属性加 1),然后再赋值给目标属性。

Atlas 提供一些内建的 transformer,例如 Add,Multiply,Compare 等。然而在实际开发中,大多数情

况下我们都需要定义自己的 transformer。让我们通过开发一个 CustomBooleanTransformer 的例子来熟

悉如何书写自定义的 transformer。

博客园 @ Dflying 版权所有 70/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

CustomBooleanTransformer 用来将布尔值转换为我们自定义的格式,例如 Yes/No 或者

Completed/InProgress。如果我们选择使用绑定来将一个布尔值显示给用户,那么这个 transformer 将会

是十分有用的,它带给用户更加友好的用户体验。

大体上,创建一个 transformer 将有如下四个步骤:

1. 取得从源绑定对象中传入的将被转换的值。这里我们首先调用 get_value()取得传入的值,并将其转

换为布尔型。

2. 取得 transformer 的参数。这里的参数是一个可以被逗号(,)分成两部分的字符串。布尔值 true

将被转换为第一部分,false 将被转换为第二部分。如果传入的参数为空,则用默认的字符串

true/false 代替。

3. 进行转换。在这个步骤应当通过您自己的逻辑把传入的值转换成将要传出的值(一般会用到上一步骤

中取得的 transformer 的参数)


。这里我们首先用逗号(,
)将参数分成两个部分,然后用第一部分

代替 true,用第二部分代替 false。如果参数不能被分成两个部分,那么使用 true/false 代替。

4. 将转换后的值输出,调用方法 set_value()来实现。

下面是 CustomBooleanTransformer 的 JavaScript 代码,将其保存为 CustomBooleanTransformer.js。

Sys.BindingBase.Transformers.CustomBoolean = function(sender, eventArgs) {


// step 1, get input value.
var value = eventArgs.get_value();
if (typeof(value) != 'boolean') {
value = Boolean.parse(value);
}

// step 2, get arguments will be used in trasforming.


var customString = eventArgs.get_transformerArgument();
if (customString == null || customString == '') {
customString = 'true,false';
}

// step 3, do the transformation.


var customValues = customString.split(',');
if (customValues.length != 2)
{
customValues[0] = 'true';
customValues[1] = 'false';
}

博客园 @ Dflying 版权所有 71/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

var newValue = value ? customValues[0] : customValues[1];

// step 4, set the transformed value as output.


eventArgs.set_value(newValue);
}

OK,现在让我们测试一下这个 CustomBooleanTransformer。在页面上添加一个 checkbox 和一个

textbox 并将他们绑定起来。当 checkbox 被选中/取消选中时,textbox 中会显示相应的被转换后的布尔值。

下面是 ASPX 文件中的 HTML 定义。不要忘记在 ScriptManager 中添加对

CustomBooleanTransformer.js 文件的引用。

<atlas:ScriptManager ID="sm1" runat="server">


<Scripts>
<atlas:ScriptReference Path="CustomBooleanTransformer.js" />
</Scripts>
</atlas:ScriptManager>
<input id="myCheckbox" type="checkbox" />
<input id="myTextbox" type="text" />

下面是 Atlas 脚本定义。这里指定 tranformerArgument 为‘Yes,No’,以期让布尔值 true 转化为 Yes,false

转化为 No。

<page xmlns:script="http://schemas.microsoft.com/xml-script/2005">
<references>
</references>
<components>
<checkBox id="myCheckbox" />
<textBox id="myTextBox">
<bindings>
<binding dataContext="myCheckbox" dataPath="checked"
property="text" transform="CustomBoolean" transformerArgument="Yes,No" /
>
</bindings>
</textBox>
</components>
</page>

博客园 @ Dflying 版权所有 72/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

浏览器中的实际结果:

E. 创建自定义的 Validator

Validator 是 ASP.NET Atlas 中的一类强大的组件,用来检查 InputControl 类型的 Atlas 控件,例如

Web.UI.TextBox,的输入数据。如果你熟悉 ASP.NET 的话,你一定知道 ASP.NET 中作为服务器控件运

行的 Validator。Atlas 中的 Validator 在客户端提供同样的功能。Atlas 包含如下一些内建的 Validator:

1. requiredFieldValidator:检查是否有数据输入。

2. typeValidator:检查输入的数据是否为特定的类型。

3. rangeValidator:检查输入的值是否在一个范围之内。

博客园 @ Dflying 版权所有 73/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

4. customValidator:用自定义的验证函数验证输入。

5. regexValidator:用指定的正则表达式验证输入。

某个 Atlas 客户端控件的 Validator 可被定义成一个集合,当控件的 propertyChanged 事件被引发时,Atlas

将调用 Validator 集合中的所有 Validator 去验证输入的数据。在验证的过程中一旦失败,这个 Validator

的 validationMessage 将被设置。Validator 可以以组的形式验证一组控件的输入,并统一显示错误信息。

您还可以指定一个 validationErrorLabel 控件关联于某个将被验证的输入控件,它可以显示验证过程中的错

误并可以自定义错误提示。

OK,以上内容大部分来自 Atlas 的文档,这里不再赘述。让我们通过一个 IPAddressValidator 的实例

来学习如何编写自定义的 Validator。顾名思义,IPAddressValidator 将用于验证某个输入是否为一个合法

的 IPv4 地址。

通常的,编写自定义 Validator 有如下两个步骤:

1. 从 Sys.UI.Validator 基类中继承。

2. 实现 validate()方法来验证输入,并返回一个布尔值代表是否验证成功。

下面是 IPAddressValidator 的实现,并将其保存为 IPAddressValidator.js。

Sys.UI.IPAddressValidator = function() {

Sys.UI.IPAddressValidator.initializeBase(this);

this.validate = function(value) {

if (!value) {

return false;

if (String.isInstanceOfType(value)) {

if (value.length == 0) {

return false;

博客园 @ Dflying 版权所有 74/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

var ipPattern = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;

var ipArray = value.match(ipPattern);

if (ipArray == null)

return false;

for (i = 0; i < 4; i++) {

var thisSegment = ipArray[i];

if (thisSegment > 255) {

return false;

return true;

Sys.UI.IPAddressValidator.registerSealedClass('Sys.UI.IPAddressValidator', Sys.UI.Validator);

Sys.TypeDescriptor.addType('script', 'ipAddressValidator', Sys.UI.IPAddressValidator);

让我们在页面中测试上面的 IPAddressValidator 控件。这里将添加一个 text box 用于待验证 IP 地址的输

入,一个 label 用于显示错误信息。

这里是 ASPX 中的 HTML 声明,不要忘记在 ScriptManager 中添加对上面 IPAddressValidator.js 文件的

引用。

<atlas:ScriptManager runat="server" ID="ScriptManager1">

<Scripts>

<atlas:ScriptReference Path="IPAddressValidator.js" />

博客园 @ Dflying 版权所有 75/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

</Scripts>

</atlas:ScriptManager>

<div class="description">

Please input an IP Address:

<input type="text" id="ipBox" class="input" />

<span id="ipValidator" style="color: red">This IP Address is invalid!</span>

</div>

下面是 Atlas 脚本定义:

<page xmlns:script="http://schemas.microsoft.com/xml-script/2005">
<components>
<textBox id="ipBox">
<validators>
<ipAddressValidator errorMessage="This IP Address is invalid!" />
</validators>
</textBox>
<validationErrorLabel id="ipValidator" associatedControl="ipBox" />
</components>
</page>

在浏览器中运行结果:

博客园 @ Dflying 版权所有 76/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

F. 随输入内容自动调整行数的 Textarea

好多朋友使用过 Outlook 或者 Windows Live Mail:在撰写新邮件时,您会发现初始的收件人文本框只有

一行。但如果您输入了好多地址,超过了一行的长度,它会自动地变成两行,如果不够,还会变成三行,四

行等。这种文本框既节约了初始空间,又让用户输入大量数据时不感到局促。为了让您对其有更直观的了解

或是有些朋友没有用到过上述产品,请看下面的截图:

初始只有两行: 当您继续输入时,行数会自动增加:

当增加到设定的最大数目(这里是 5)时, 这时如果您删除了其中的一些文字,

滚动条依然会出现: 行数也会随之自动减少:

博客园 @ Dflying 版权所有 77/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

怎么样,很酷吧?如果您正在使用 ASP.NET Atlas,那么实现这样的功能是非常简单的,您只需要


创建一个输入控件:AutoResizeTextArea

1. 充分利用 Atlas 提供的强大的 JavaScript 面向对象功能,继承于 Sys.UI.TextBox 类,重用父类

的基础功能。

2. 捕获 DOM 的 onkeyup 事件,并计算是否超过了这个 textarea 可容纳的文字数量,以动态调整该

textarea 的行数。这是本控件实现中比较有“技术含量”的部分,您可以参考源文件以得到具体实现。

AutoResizeTextArea 有如下两个属性:

1. minRowCount:该 textarea 最少的行数,默认值和 textarea 声明中的 rows 属性相同,如果

textarea 没有声明 rows 属性,那么默认值为 3。

2. maxRowCount:该 textarea 最多的行数,默认值为 7。

这里您可以很容易的扩展或重写我的逻辑,比如,将 maxRowCount 属性的默认值改为无穷大


等。

使用 AutoResizeTextArea 控件要注意以下两点:

1. ScriptManager 中要添加 AutoResizeTextArea.js 文件的引用。

2. 作为 AutoResizeTextArea 控件的源 DOM 元素必须为 textarea,我的代码中没有对相关元素的

检查,如果您需要,可以很容易的添加上去。

该控件的源代码以及开头部分示例程序可以在此下载:
http://www.cnblogs.com/Files/dflying/AutoResizeTextArea.zip

博客园 @ Dflying 版权所有 78/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

G. 实现拖放(Drag & Drop)效果(上)

ASP.NET Atlas 提供了一个简单易用而又强大的跨浏览器的拖放功能的实现。Atlas 的拖放功能实现位于

AtlasUIDragDrop.js 文件中,感兴趣的朋友可以学习一下它的实现,当然,这部分内容不在本文的范围之

内(今后应该会有所介绍,希望我不会懒)。

基本上,Atlas 中可拖放的 UI 由如下两个部分实现:

1. 可拖动的对象以及投放目标对象。可拖动的对象就是在页面中可以被鼠标移动的 DOM 元素(例如网

上商城中的物品),而投放目标对象则是页面中可以接收可拖动对象的,作为容器的 DOM 元素(例

。Atlas 允许您通过实现 IDragSource 接口来定义自己的可拖动对象,实


如网上商城中的购物车)

现 IDropTarget 接口来定义自己的投放目标对象。当然您可以同时实现上述两个接口(比如,您

希望用户可以在页面上自由拖动并安排购物车的位置)

2. 一个 DragDropManager 对象。DragDropManager 是一个全局对象,将在运行时被自动初

始化(当然,您需要在 ScriptManager 中显示声明引用 AtlasUIDragDrop 脚本)。您可以使用

Sys.UI.DragDropManager 访问到它。它的主要功能是通过调用 IDragSource 以及 IDropTarget

接口提供的方法来启动拖放操作以及注册投放目标对象。通常情况下,您不需要考虑太多关于

DragDropManager 的事情。

这样,通常情况下使用 Atlas 创建可拖放的 UI 有如下两个步骤:

1. 通过实现 IDragSource 接口来创建可拖动的对象,实现 IDragSource 接口的对象应该负责调用

DragDropManager 的 startDragDrop()方法以开始拖动的操作(通常这个步骤应该放在处理

mouse down 事件中实现)。每个可拖动的对象都有自己的 dataType 属性,可以用来定义相同类

型拖放对象。

2. 通过实现 IDropTarget 接口来创建投放目标对象,实现 IDropTarget 接口的对象应该在

DragDropManager 中调用 registerDropTarget()注册自己。每个投放目标对象都有自己的

acceptedDataTypes 属性,用来指定该投放目标对象可以接受何种 dataType 属性的可拖动对

象。

博客园 @ Dflying 版权所有 79/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

总体上,拖放操作开始于一个可拖动对象调用 DragDropManager 的 startDragDrop()方法,然后,

DragDropManager 接管了其它的操作,它将负责调用可拖动对象的 IDragSource 接口方法以及投放目标

对象的 IDropTarget 接口方法来协调二者的关系,以及相应的 UI 变化。

Atlas提供了一些内建的实现了IDragSource以及IDropTarget接口的Behavior(关于Behavior,请
参考:在ASP.NET Atlas中创建自定义的Behavior)供我们使用。显然,下列客户端Behavior都实

现了IDragSource或IDropTarget接口中的至少一个。

1. DragDropList Behavior可以为一组控件增加拖放功能。典型应用就是使ListView控件(关于

ListView,请参考:使用ASP.NET Atlas ListView控件显示列表数据)实现拖放功能。

2. DraggableListItem Behavior 可以在一个 DragDropList 中定义一个拖动对象。可以应用在

ListView 的 ItemTemplate 上,使列表中的每一项都可以拖动。

3. DataSourceDropTarget Behavior用来把数据通过拖放的方式加入到DataSource控件(关于

DataSource,请参考:Atlas命名空间Sys.Data下控件介绍——DataSource和XMLDataSource)

中。

4. FloatingBehavior Behavior 可以使某个控件浮动在页面上,并可随意移动。

在下篇中我将通过一个示例程序来演示拖放(Drag & Drop)效果的实现:使用ASP.NET Atlas


实现拖放(Drag & Drop)效果(下)

H. 实现拖放(Drag & Drop)效果(下)

在本篇中我将使用Atlas的DragDropList Behavior配合Atlas的ListView控件(关于ListView,请
参考:使用ASP.NET Atlas ListView控件显示列表数据)来实现一个用户可通过拖拽重新排列内容

的页面。大概类似 Start与 Windows Live的样子,或者,如果你熟悉ASP.NET中的Web Parts,也


差不多。当然,这里仅仅是一个演示,不可能做出同样复杂的功能和眩目的效果。您可以在本文的最后

下载到这个DEMO的源文件。

首先,一个 ScriptManager 是必不可少的,不要忘记在其中引入 AtlasUIDragDrop 脚本文件,它不是

Atlas 默认加载的。

博客园 @ Dflying 版权所有 80/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

<atlas:ScriptManager ID="scriptManager" runat="server">


<Scripts>
<atlas:ScriptReference ScriptName="AtlasUIDragDrop" />
</Scripts>
</atlas:ScriptManager>

然后,让我们在页面上添加一个静态的布局,这将是用户加载页面之后看到的初始布局,然后再考虑添加动

态的 Atlas 标记使其能够自由拖动。这里我将创建左右两个区域,区域中的内容既可以在区域之间拖动以改

变布局,也可以在本区域内拖动以改变顺序。可拖拽的部分将被包含在一个 div 中,内部包含任意的控件(可

为 ASP.NET 服务器端控件)。

<!-- Left Area -->


<div id="leftArea" class="list1">
<div id="content1" class="item">
<div id="content1Title" class="itemTitle">Content 1</div>
<div class="itemContent">
<asp:Login ID="myLogin" runat="server"></asp:Login>
</div>
</div>
<div id="content2" class="item">
<div id="content2Title" class="itemTitle">Content 2</div>
<div class="itemContent">
Dflying's Item
</div>
</div>
</div>
<!-- Right Area -->
<div id="rightArea" class="list2">
<div id="content3" class="item">
<div id="content3Title" class="itemTitle">Content 3</div>
<div class="itemContent">
<asp:Calendar ID="myCalendar" runat="server" CssClass="centered"></asp:Calen
dar>
</div>
</div>
</div>

在上面的代码中,我加入了两个区域和三个 panel,声明了页面的初始样子。下面让我们加入两
个模版:一个用来表示当拖动元素经过可投放区域时,可投放区域高亮的样式(dropCueTemplate)。

一个用来表示当某个可投放区域为空的时候的样式(emptyTemplate)。

博客园 @ Dflying 版权所有 81/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

<!-- Hide template elements -->


<div style="display:none;">
<!-- DropCue Template -->
<div id="dropCueTemplate" class="dropCue">
</div>
<!-- Empty Template -->
<div id="emptyTemplate" class="emptyList">
Drop content here.
</div>
</div>

恩,还有一些 CSS 的定义,为方便您的理解,也列在下面:

body, input {font-family:Verdana; font-size: 0.7em;}


.list1{width: 45%; float: left}
.list2{width: 45%; float: right}
.item{background:#fff;}
.itemContent{padding:5px;text-align:center;}
.itemTitle{background:#e5ecf9;font-weight:bold;cursor:move;}
.dropCue{border:dashed 1px #ff0000;}
.emptyList{text-align:center;}

OK,现在可以添加 Atlas 标记让页面真得动起来了:)上面定义的两个投放区域将被添加 DragDropList

Behavior 以成为 Atlas 控件。

<!-- Left Area -->


<control id="leftArea">
<behaviors>
<dragDropList dataType="HTML" acceptedDataTypes="'HTML'" dragMode="Move" directi
on="Vertical">
<dropCueTemplate>
<template layoutElement="dropCueTemplate" />
</dropCueTemplate>
<emptyTemplate>
<template layoutElement="emptyTemplate" />
</emptyTemplate>
</dragDropList>
</behaviors>
</control>

<!-- Right Area -->


<control id="rightArea">
<behaviors>

博客园 @ Dflying 版权所有 82/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

<dragDropList dataType="HTML" acceptedDataTypes="'HTML'" dragMode="Move" directi


on="Vertical">
<dropCueTemplate>
<template layoutElement="dropCueTemplate" />
</dropCueTemplate>
<emptyTemplate>
<template layoutElement="emptyTemplate" />
</emptyTemplate>
</dragDropList>
</behaviors>
</control>

在上面的代码中,我们将 leftArea 以及 rightArea 提升为 Atlas 控件,并且添加了 DragDropList


Behavior。这两个 DragDropList 包含了一些类型为 HTML 的内容,也将可以接受类型为 HTML 的
内容被投放在其中(由 dataType 以及 acceptedDataTypes 属性设定)。这两个 DragDropList 排
列内容的方向为 Vertical(可以为 Vertical 或者 Horizontal,由 direction 属性设定)。并且拖拽

的方式为 Move(可以为 Move 或者 Copy,前者将拖动元素移动,移动后原处不再存在;后者


将拖动元素拷贝,移动后原处还存在。由 dragMode 属性设定)。还指定了上面定义
dropCueTemplate 和 emptyTemplate 两个模版。

下面来定义可拖动的元素:

<!-- Draggable items -->


<control id="content1">
<behaviors>
<draggableListItem handle="content1Title" />
</behaviors>
</control>
<control id="content2">
<behaviors>
<draggableListItem handle="content2Title" />
</behaviors>
</control>
<control id="content3">
<behaviors>
<draggableListItem handle="content3Title" />
</behaviors>
</control>

博客园 @ Dflying 版权所有 83/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

同样的,在上面的代码中,我们将三个 panel 提升为 Atlas 控件,并添加了 DraggableListItem


Behavior。这个 Behavior 将允许被定义的元素可以被拖动。handle 属性定义了可拖动的部分(类
似于 Window 窗口中的标题栏)。

现在我们可以测试一下了:

初始:

博客园 @ Dflying 版权所有 84/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

开始拖动左边的 Calendar,您可以看到 dropCueTemplate 显示了出来(右面红色的虚线框)。


页面的下方同时自动出现了 Debugging Trace 的提示,很方便调试:

博客园 @ Dflying 版权所有 85/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

将 Calendar 拖到右面的列表中,左边只剩下了一个可拖动元素:

博客园 @ Dflying 版权所有 86/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

把左边的可拖动元素也拖到右面,您可以看到 emptyTemplate:

该示例程序可在此下载:http://www.cnblogs.com/Files/dflying/AtlasDragDropDemo.zip

I. In Place Editing 输入控件

可能有些朋友还不了解什么是 In Place Editing(不知道怎么翻译),请先看一下下面的 DEMO


(首页:

博客园 @ Dflying 版权所有 87/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

上面三个输入在平时就是普通的 Label,鼠标悬停在上面时会有边框出现。当用户点击这个 Label

时,切换到 Input 状态。用户输入完毕鼠标移开,又会切换回 Label 状态,提供了丰富的用户视觉

体验,同时也节约了页面空间。该控件是我匆促之间(一个小时)完成,好多代码组织混乱,可能

也会有不少 Bug,仅供各位参考并请不吝指正。

InPlaceEditingInput 控件有如下五个属性,当然,您可以很容易的扩充:

1. toolTipText:该输入控件的初始文字提示。上面 DEMO 中的“Enter Your Name”就是制定的这

个属性。

2. toolTipTextColor:该输入控件的初始文字的颜色,默认值为#aaa。您可以看到上面 DEMO 中

的“Enter Your Name”的颜色与用户实际输入的文字颜色不一样,稍微浅了一点。

3. labelColor:该控件作为 Label 显示时的颜色,默认值为 white。

4. inputBorderColor:该控件作为 Input 显示时的边框颜色,默认值为 black。

5. inputBgColor:该控件作为 Input 显示时的背景颜色,默认值为#f2f2f9(淡蓝色)。

使用 InPlaceEditingInput 控件要注意以下几点:

1. ScriptManager 中要添加 InPlaceEditingInput.js 文件的引用。

2. 作为 InPlaceEditingInput 控件的源 DOM 元素必须为 input 或者 textarea。

3. 您应该为每个 InPlaceEditingInput 控件指定 toolTipText 属性,以带来好的用户体验。

该控件的主要开发思路为:

博客园 @ Dflying 版权所有 88/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

1. 充分利用 Atlas 提供的强大的 JavaScript 面向对象功能,继承于 Sys.UI.TextBox 类。

2. 捕获 HTML 的 onmouseover,onmouseout,onfocus 以及 onblur 事件,并应用相应的 CSS 样

式。

该控件的源代码以及开头部分示例程序可以在此下载:
http://www.cnblogs.com/Files/dflying/InPlaceEditingDemo.zip

J. 结合 Membership 进行身份验证

ASP.NET Atlas 可以使用 ASP.NET 中的 Membership 来进行用户身份验证,并在验证成功后自动设定相

应的 Cookie。Atlas 中的身份验证是通过 Sys.Services._AuthenticationService 类的一个实例:

Sys.Services.AuthenticationService 来进行的,在 Atlas 应用程序中,您可以通过这个全局的

Sys.Services.AuthenticationService 对象来进新身份验证。

Sys.Services.AuthenticationService 对象有如下几个方法:

1. validateUser():该方法接受用户名,密码两个参数,并将返回一个布尔值代表用户验证(注意,

仅仅为验证,不是登录,该方法将不会设置 Cookie。)是否成功。该方法将使用 ASP.NET 中设置的

默认的 membership provider 来进行用户的验证。

2. login():这个方法与 validateUser()方法类似,但在其基础上该方法会设置代表登录成功的

Cookie,当然需要在提供的用户名/密码正确的情况下。通过调用这个方法,您可以实现 AJAX 方式

的用户登录。

3. logout():注销当前用户。

下面我们通过一个例子来演示一下使用 Sys.Services.AuthenticationService 对象进行用户身份验证。

首先,在您的 web.config 文件中启用相应的验证服务:

<configSections>

<sectionGroup name="microsoft.web" type="Microsoft.Web.Configuration.MicrosoftWeb

SectionGroup">

<section name="converters" type="Microsoft.Web.Configuration.ConvertersSection" r

equirePermission="false"/>

博客园 @ Dflying 版权所有 89/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

<section name="webServices" type="Microsoft.Web.Configuration.WebServicesSectio

n" requirePermission="false"/>

<section name="authenticationService" type="Microsoft.Web.Configuration.Authentic

ationServiceSection" requirePermission="false"/>

<section name="profileService" type="Microsoft.Web.Configuration.ProfileServiceSect

ion" requirePermission="false"/>

</sectionGroup>

</configSections>

还有:

<microsoft.web>

<webServices enableBrowserAccess="true"/>

<!--

Uncomment this line to enable the authentication service.-->

<authenticationService enabled="true" />

</microsoft.web>

然后我们在 Membership 数据库中添加几个测试的用户,您可以通过 ASP.NET Web Site Administration

Tool 来设置并添加用户。

现在我们创建一个简单的登录页面,与所有的登录页面类似,两个 input(用户名/密码)一个按钮(登录)。

我们又加入了一个 label 来显示用户登录信息。代码如下:

Status: <span style="color: Red;" id="status">logged out</span><br />

User Name:<input type="text" id="username" /><br />

Password:<input type="password" id="password" /><br />

<input id="loginlogout" type="button" onclick="OnSubmitLogin()" value="Click me to login!

" /><br />

当然,最重要的 ScriptManager 是不能缺少的:

<atlas:ScriptManager ID="scriptManager" runat="server" />

博客园 @ Dflying 版权所有 90/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

下面,我们来书写登录按钮按下时候的事件处理函数,也就是登录的处理。首先,利用 Atlas 的$()方法在

DOM 中找到上述几个 HTML 控件:

var username = $('username');

var password = $('password');

var status = $('status');

var buttonLoginLogout = $('loginlogout');

下面是用户登录时的处理,注意到我们只是简单的调用了 Sys.Services.AuthenticationService.login()

方法,并在返回以后相应改变状态 label 的文字:

function OnSubmitLogin() {

Sys.Services.AuthenticationService.login(username.value, password.value, false, OnLogi

nComplete);

return false;

function OnLoginComplete(result) {

password.value = '';

//On success there will be a forms authentication cookie in the browser.

if (result) {

username.value = '';

status.innerHTML = "logged in";

buttonLoginLogout.innerText = "Click me to logout!";

buttonLoginLogout.onclick = OnSubmitLogout;

else {

status.innerHTML = "User name/Password not match!";

博客园 @ Dflying 版权所有 91/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

下面是用户注销时的处理,通过调用 Sys.Services.AuthenticationService.logout()方法来实现:

function OnSubmitLogout() {

//This call will cause the server to clear the forms authentication cookie.

Sys.Services.AuthenticationService.logout(OnLogoutComplete);

return false;

function OnLogoutComplete(result) {

buttonLoginLogout.innerText = "Click me to login!";

status.innerHTML = "logged out";

buttonLoginLogout.onclick = OnSubmitLogin;

以上实例程序可以在此下载:http://www.cnblogs.com/Files/dflying/AuthenticationTest.zip

在下载的文件中我添加了一个 SecuredFolder 文件夹,其中内容只有登录后的用户才能访问,以便朋友们测

试。

博客园 @ Dflying 版权所有 92/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

第五章 Atlas 其它篇

A. 在 Atlas 服务器端实现中推荐使用 Web Service 而不是 Page Method

我们可以用两种方式把一个服务器段方法暴露给客户端 Atlas调用:Web Service和Page


Method。我推荐使用Web Service的方法。

所有人都应该非常重视的一点是Web Service和Page Method的工作原理以及工作过程有很大的分

别。对于 Atlas调用Web Service来说,当请求被发送时候,仅仅简单传给服务器方法的参数数据。而

对于 Atlas调用Page Method来说,传输的数据将会很多,将把表单中所有的域,包括ViewState,一

起传送到服务器。在服务器端,它的工作方式也和普通的PostBack很相似:在这个Page Method被调

用前,所有的服务器控件将得到它自身的状态。这也正是为什么Page Method中可以访问页面中控件状

态的原因。

因此我的建议是只要在确实需要使用 Page Method 的时候(比如说需要在 Page Method 中访问页面中的

控件状态)才使用 Page Method,否则尽可能多地使用 Web Service,这样可以使程序在性能上有所提高。

使用 Web Service 的另一个好处是让程序层次架构明晰。

您可以在 http://www.fiddlertool.com/fiddler/下载Fiddler,一个很好的HTTP watcher和


debugger,用来监视客户端与服务器的实际HTTP通信内容。

这里是一段 Web Method,只是简单的返回服务器的当前时间。

[WebMethod]
public DateTime GetCurrentDateTime()
{
return DateTime.Now;
}

让我们分别以 Web Service 和 Page Method 运行这一段 Web Method,并用 Fiddler 观察实际运行时的

HTTP 通信内容:

博客园 @ Dflying 版权所有 93/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

Web Service

博客园 @ Dflying 版权所有 94/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

Page Method

可以看到以 Web Service 方式运行时 Post 回服务器的 Content-Length 为 0,而以 Page Method 运行时

候为 1718。

B. 调试 Atlas 客户端 JavaScript 脚本

介绍

编写 Atlas 的 JavaScript 脚本将比编写 C# 更具有挑战性,因为 JavaScript 没有编译时期检查,在编码时

候也没有智能感知提示。并且您还需要在运行时跟踪服务器和客户端的网络通信。而且目前还没有一个非常

强大的 JavaScript IDE 可以帮您分担其中繁杂的工作。

我在工作中使用 Atlas 有半年左右,其中积累了一些关于调试 Atlas 程序得知识与经验,希望能与大家分享。

其中疏漏之处,还请多多指正。

博客园 @ Dflying 版权所有 95/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

捕获 HTTP 通信内容

在任何的 AJAX 程序开发中,监视服务器与客户端的通信内容都是非常重要的。这样您可以得知我实际上像

服务器发送了什么以及服务器实际上给我返回了什么。当您的 Atlas 程序遇到问题时,首先要考虑的就是查

看一下客户端与服务器端的通信,看看通信的内容是不是您所期盼的。

这里我推荐的工具是Fiddler(可以在 http://www.fiddlertool.com/fiddler/下载)。Fiddler是一
个HTTP调试的代理,它可以记录您的计算机和Internet之间HTTP通信的全部内容(包括header,

cookie,通信内容等),设置断点,修改传入/传出的数据等。Fiddler比NetMon或Achilles等同类软

件简单得多,并且提供了一个简单但强大的基于JScript.NET的事件的脚本子系统。Fiddler支持

Internet Explorer以及其它浏览器。

博客园 @ Dflying 版权所有 96/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

下面是 Fiddler 的运行时截图:

使用 Atlas Debug Helper Class

如果您的 Atlas 程序运行在 debug 模式下,那么 Atlas 会自动为您生成一个 Debug Helper Class。 这

个 Debug Helper Class 是一个全局的对象,名称为 debug,可以在您代码的任何部位被访问到。使用

这个 debug 对象的方法,您可以在运行时 dump 一个对象(以可读的形式在页面尾部显示该对象的内

部状态),显示 trace 信息,使用断言(assertion),break 到调试器等。如果 Visual Studio 的脚

本调试器(参见下文)已经 attach 到了这个 Internet Explorer 上,那么 Visual Studio 的 Output

窗口也会显示 trace 信息。

博客园 @ Dflying 版权所有 97/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

这个 Debug Helper Class 提供如下方法:

1. debug.assert(condition, message, displayCaller)

断言 condition 是否为 true。如果 condition 为 false,该方法将显示出 message 的内容。如

果 displayCaller 为 true,该方法将显示出调用者的信息。

2. debug.clearTrace()

清除 trace 的输出。

3. debug.dump(object, name, recursive, indentationPadding)

以可读的形式在页面尾部显示 object 对象的内部状态。name 值用来显示该对象的名称。如果

recursive 为 true,将递归显示该对象内部的所有被包含的对象的信息。indentationPadding

值用来指定输出的每一行的起始文本。

4. debug.fail(message)

Break 到调试器中。(仅应用于 Internet Explorer 中)

5. debug.trace(text)

将 text 参数输出到 trace 当中。

演示如何使用 debug.dump()请见参考文档

将 Visual Studio 脚本调试器 attach 到 Internet Explorer

您可以使用 Visual Studio 脚本调试器来调试您的 JavaScript 代码。虽然这个调试器功能有限且有许多 bug,

不过我觉得它已经是此刻市面上最好的 JavaScript 调试器了。您需要安装 Visual Studio 2005 以及

Internet Explorer 6.0 或以上版本来使用 Visual Studio 脚本调试器。

在默认情况下,Internet Explorer 将忽略所有 JavaScript 脚本错误。您需要手动设置一些属性来


使 Internet Explorer 启用调试功能。打开 Internet Explorer 窗口,在 Tools 菜单下选择 Internet

Options,在 Advanced 标签中,不要选中 Disable Script Debugging (Internet Explorer)和 Disable

Script Debugging (Other)两项,并选中 Display a notification about every script error 一项。

您需要 attach 调试器到 Internet Explorer 进程上以开始 debug。在 Visual Studio 中使用 F5 来启

动调试即可。还有一种方法,您可以将 Visual Studio 脚本调试器 attach 到已经在运行的某个 Internet

Explorer 进程上:在 Internet Explorer 的 View 菜单下,展开 Script Debugger 菜单项,选择 Open。

博客园 @ Dflying 版权所有 98/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

然后在弹出的对话框中选择一个正在运行的 Visual Studio 或是另外启动一个 Visual Studio。

脚本调试器使用技巧以及现存 Bug

调试 Atlas 应用程序时,应该注意以下问题:

1. 当 Visual Studio 脚本调试器 attach 到 Internet Explorer 上以后,您可以看到 Atlas 客户端类库

将以 WebResource.axd?...这样的一个资源文件出现在 Script 浏览器中。这是服务器端由

Microsoft.Web.Atlas.dll 程序集动态生成的。这里已知的一个 bug 是,在刚刚开始 debug 的时候

Visual Studio 可能阻止你打开这个文件。也就是说当您双击这个文件时候或者是没有任何反应,或

者是弹出错误提示。解决方法是先选择打开另外的 JavaScript 文件,然后再试一次重新打开,一般

就会解决。(注意这个 WebResource.axd?...是一个很大的文件,需要等待一段时间才能打开。)

2. Visual Studio 不允许您在 ASPX 文件中的 JavaScript 代码中设置断点。解决的方法有三个,一个

是从外部的 JavaScript 函数中单步跟踪到 ASPX 中的 JavaScript,一旦调试器停在了 ASPX 文件

中的 JavaScript,那么您就可以在下面的某一行设置断点了。二是在需要 break 的地方加上

debug.fail(),这样当 Visual Studio 脚本调试器 break 到此处时,您就可以在其它地方设置断点

了。三是将您所有的自定义 JavaScript 代码放置于外部文件中,并在 ASPX 中进行引用。

3. Visual Studio 不允许您在一个匿名方法(类似 this.func = function())的方法体的第一行设置断

点。您可以通过在第一行之前加入一些无意义的代码(例如 var a = 3)来使原本的第一行变成第二

行,这样即可在第二行设置相应的断点。

博客园 @ Dflying 版权所有 99/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

4. 在 debug 的过程中,当您将鼠标移到 JavaScript 的某个变量上的时候,可能得到的变量值是错误

的,请看如下的截图,提示 length 为 0,实际上应该为 10。

此时您应该选中(高亮)从对象到属性的所有语句,然后再将鼠标移到被选中的内容上,即可得到正

确的值。请见下图:

5. 有时候在某次 debug 之后发现 Internet Explorer 中的 Script Debugger 菜单项消失了,这时

您可以重新打开一个 Internet Explorer 窗口,即可找回这个丢失的菜单项。

参考资源

1. http://atlas.asp.net/docs/Overview/debug.aspx

C. The XMLHttpRequest Object

W3C Working Draft 05 April 2006


This version:
http://www.w3.org/TR/2006/WD-XMLHttpRequest-20060405/

博客园 @ Dflying 版权所有 100/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

Latest version:
http://www.w3.org/TR/XMLHttpRequest
Editors:
Anne van Kesteren (Opera Software ASA) <annevk@opera.com>
Dean Jackson (W3C) <dino@w3.org>

Copyright ©2006 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C liability,
trademark and document use rules apply.

Abstract

This specification defines the XMLHttpRequest object, an API that provides some HTTP client
functionality.

Status of this Document

This section describes the status of this document at the time of its publication. Other documents may
supersede this document. A list of current W3C publications and the latest revision of this technical
report can be found in the W3C technical reports index at http://www.w3.org/TR/.

This is the 05 April 2006 Working Draft of the XMLHttpRequest Object, the first publication of this
specification. This document is produced by the Web API WG, part of the Rich Web Clients Activity in
the W3C Interaction Domain. The authors of this document are the members of the W3C Web API
Working Group.

Web content and browser developers are encouraged to review this draft. Please send comments to
public-webapi@w3.org, the W3C's public email list for issues related to Web APIs. Archives of the list
are available.

This document was produced by a group operating under the 5 February 2004 W3C Patent Policy.
This document is informative only. W3C maintains a public list of any patent disclosures made in
connection with the deliverables of the group; that page also includes instructions for disclosing a
patent. An individual who has actual knowledge of a patent which the individual believes contains
Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent
Policy.

Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft
document and may be updated, replaced or obsoleted by other documents at any time. It is
inappropriate to cite this document as other than work in progress.

博客园 @ Dflying 版权所有 101/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

Table of Contents

• 1. Introduction
• 2. Conformance
• 3. The XMLHttpRequest object

• A. References
• B. Authors

1. Introduction

This section is informative

The XMLHttpRequest object is an interface exposed by a scripting engine that allows scripts to
perform HTTP client functionality, such as submitting form data or loading data from a remove Web
site.

The XMLHttpRequest object is implemented today, in some form, by many popular Web browsers.
Unfortunately the implementations are not completely interoperable. The goal of this specification is to
document a minimum set of interoperable features based on existing implementations, allowing Web
developers to use these features without platform-specific code. In order to do this, only features that
are already implemented are considered. In the case where there is a feature with no interoperable
implementations, the authors have specified what they believe to be the most correct behavior.

Future versions of this specification (as opposed to future drafts of this version) may add new features,
after careful examination from browser developers and Web content developers.

This specification was originally derived from the WHAT WG's Web Applications 1.0 document. The
authors acknowledge the work of the WHAT WG in documenting existing behavior.

2. Conformance

This section is normative

The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT,
RECOMMENDED, MAY, and OPTIONAL in this document are to be interpreted as described in RFC
2119 [RFC2119].

3. The XMLHttpRequest object

This section is normative

The following interface MAY be used to allow scripts to programmatically connect to their originating
server via HTTP.

博客园 @ Dflying 版权所有 102/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

In ECMAScript, an instance of XMLHttpRequest can be created using the XMLHttpRequest()


constructor:

Example: XMLHttpRequest constructor

var r = new XMLHttpRequest();

What about non-ECMAScript implementations?

A more complete description of what can be done with XMLHttpRequest can be found in the IDL
below and its associated details.

Need to define which IDL specification we are going to conform to, if any.

The XMLHttpRequest interface

interface XMLHttpRequest {

attribute Function onreadystatechange;


readonly attribute unsigned short readyState;
void open(in DOMString method, in DOMString uri);
void open(in DOMString method, in DOMString uri, in boolean
async);
void open(in DOMString method, in DOMString uri, in boolean
async, in DOMString user);
void open(in DOMString method, in DOMString uri, in boolean
async, in DOMString user, in DOMString password);
void setRequestHeader(in DOMString header, in DOMString
value)

raises(DOMException);

void send(in DOMString data)

raises(DOMException);

void send(in Document data)

raises(DOMException);

void abort();
DOMString getAllResponseHeaders();

博客园 @ Dflying 版权所有 103/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

DOMString getResponseHeader(in DOMString header);


attribute DOMString responseText;
attribute Document responseXML;
attribute unsigned short status;

// raises(DOMException) on
retrieval

attribute DOMString statusText;

// raises(DOMException) on
retrieval

};

Attributes

onreadystatechange of type Function

An attribute that represents a function that MUST be invoked when readyState changes
value. The function MAY be invoked multiple times when readyState is 3 (Receiving). Its initial
value MUST be null.

What if languages don't have functions? Perhaps this should be an EventListener?


readyState of type unsigned short, readonly

The state of the object. The attribute MUSt be one of the following values:

0 Uninitialized
The initial value.
1 Open
The open() method has been successfully called.
2 Sent
The UA successfully completed the request, but no data has yet been received.
3 Receiving
Immediately before receiving the message body (if any). All HTTP headers have been
received.
What about HEAD requests?
4 Loaded
The data transfer has been completed.
responseText of type DOMString

If the readyState attribute has a value other than 3 (Receiving) or 4 (Loaded), it MUST be
the empty string. Otherwise, it MUST be the the body of the data received so far, interpreted

博客园 @ Dflying 版权所有 104/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

using the character encoding specified in the response, or UTF-8 if no character encoding was
specified. Invalid bytes MUST be converted to U+FFFD REPLACEMENT CHARACTER.

responseXML of type Document

If the readyState attribute has a value other than 4 (Loaded), it MUST be null.
Otherwise, if the Content-Type header contains a media type (ignoring any parameters)
that is either text/xml, application/xml, or ends in +xml, it MUST be an object
that implements the Document interface representing the parsed document. If the document
was not an XML document, or if the document could not be parsed (due to an XML
well-formedness error or unsupported character encoding, for instance), it MUST be null.

status of type unsigned short

If the status attribute is not available it MUST raise an exception. It MUST be available
when readyState is 3 (Receiving) or 4 (Loaded). When available, it MUST represent the
HTTP status code (typically 200 for a successful connection).

Exceptions on retrieval
DOMException INVALID_STATE_ERR SHOULD be raised if this attribute is accessed when
readyState has an inappropriate value.
statusText of type DOMString

If the statusText attribute is not available it MUST raise an exception. It MUST be


available when readyState is 3 (Receiving) or 4 (Loaded). When available, it MUST
represent the HTTP status text sent by the server (appears after the status code).

Exceptions on retrieval
DOMException INVALID_STATE_ERR SHOULD be raised if this attribute is accessed when
readyState has an inappropriate value.

Methods

abort

When invoked, this method MUST cancels any network activity for which the object is
responsible and resets the object.

No Parameters
No Return Value
No Exceptions
getAllResponseHeaders

博客园 @ Dflying 版权所有 105/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

If the readyState attribute has a value other than 3 (Receiving) or 4 (Loaded), it MUST
return null. Otherwise, it MUST return all the HTTP headers, as a single string, with each
header line separated by a CR (U+000D) LF (U+000A) pair. The status line MUST not be
included.

Example: Manipulating response headers

// The following script:

var r = new XMLHttpRequest();

r.open('get', 'test.txt', false);

r.send();

alert(r.getAllResponseHeaders());

// ...should display a dialog with text similar to the following:

Date: Sun, 24 Oct 2004 04:58:38 GMT

Server: Apache/1.3.31 (Unix)

Keep-Alive: timeout=15, max=99

Connection: Keep-Alive

Transfer-Encoding: chunked

Content-Type: text/plain; charset=utf-8

No Parameters
Return Value
A single string consisting of all HTTP headers. See prose for details.
No Exceptions
getResponseHeader

If the readyState attribute has a value other than 3 (Receiving) or 4 (Loaded), it MUST
return the empty string. Otherwise, it MUST represent the value of the given HTTP header in
the data received so far for the last request sent, as a single string. If more than one header of

博客园 @ Dflying 版权所有 106/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

the given name was received, then the values MUST be concatenated, separated from each
other by an U+002C COMMA followed by an U+0020 SPACE. If no headers of that name were
received, then it MUST return the empty string. Header names MUST be compared
case-insensitively to the method argument (header).

Example: Manipulating response headers

// The following script:

var r = new XMLHttpRequest();

r.open('get', 'test.txt', false);

r.send();

alert(r.getAllResponseHeaders());

// ...should display a dialog with text similar to the following:

Date: Sun, 24 Oct 2004 04:58:38 GMT

Server: Apache/1.3.31 (Unix)

Keep-Alive: timeout=15, max=99

Connection: Keep-Alive

Transfer-Encoding: chunked

Content-Type: text/plain; charset=utf-8

Parameters
header of type DOMString
@XXX TDB@
Return Value
@XXX TBD@
No Exceptions
open

博客园 @ Dflying 版权所有 107/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

Calling this method MUST initialise the object by remembering the method, uri, async (defaulting to
true if omitted), user (defaulting to null if omitted), and password (defaulting to null if omitted)
arguments, setting the readyState attribute to 1 (Open), resetting the responseText,
responseXML, status, and statusText attributes to their initial values, and resetting the list
of request headers.

Same-origin security restrictions SHOULD apply.

If the URI given to this method contains a user name and a password (the latter potentially being the
empty string), then these MUST be used if the user and password arguments are omitted. If the
arguments are not omitted, they take precedence, even if they are null.

If open() is called when readyState is 4 (Loaded) the entire object MUST be reset.

Parameters
method of type DOMString
A valid HTTP method name. The GET, POST, and HEAD values MUST be supported.
What about PUT and DELETE?
uri of type DOMString
A URI, which MUST be resolved to an absolute URI using the script's context
window.location.href value as base if available.
This does not reflect what implementations do. document.baseURI might come closer. (
ISSUE-29)
async of type boolean, optional
@XXX TBD@
user of type DOMString, optional
@XXX TBD@
password of type DOMString, optional
@XXX TBD@
No Return Value
No Exceptions
send

If the readyState attribute has a value other than 1 (Open), an exception MUST be raised.
Otherwise, the readyState attribute MUST be set to 2 (Sent) and a request to uri using method
method, authenticating using user and password as appropriate is sent. If the async flag is set to false,
then the method MUST not return until the request has completed. Otherwise, it MUST return
immediately. (See: open().)

If the method is POST or PUT, then the data passed to the send() method MUST be used for the
entity body. If data is a string, the data MUST be encoded as UTF-8 for transmission. If the data is a
Document, then the document MUST be serialised using the encoding given by
data.xmlEncoding, if specified, or UTF-8 otherwise [DOM3]. If data is not a Document or a
DOMString the host language MUST use the stringification mechanisms on the argument that was
passed.

博客园 @ Dflying 版权所有 108/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

Implementations SHOULD support the send() to be called without the data argument to be passed.

If the response is an HTTP redirect (status code 301, 302, 303 or 307), then it MUST be transparently
followed (unless it violates security or infinite loop precautions). Any other error (including a 401)
MUST cause the object to use that error page as the response.

Immediately before processing the message body (if any), the readyState attribute MUST be set to
to 3 (Receiving). When the request has completed loading, the readyState attribute MUST be set to
4 (Loaded).

Parameters
data of varying types (see IDL)
@XXX TDB@
No Return Value
Exceptions
DOMException INVALID_STATE_ERR MUST be raised if this method is called when
readyState has an inappropriate value.
setRequestHeader

If the readyState attribute has a value other than 1 (Open), an exception MUST be raised.
If the header or value arguments contain any U+000A LINE FEED or U+000D CARRIAGE
RETURN characters, or if the header argument contains any U+0020 SPACE or U+003A
COLON charecters, nothing MUST be done. Otherwise, the request header header MUST
be set to value. If the request header header had already been set, then the new value
MUST be concatenated to the existing value using a U+002C COMMA followed by a U+0020
SPACE for separation.

Example: Setting a request header

// The following script:

var r = new XMLHttpRequest();

r.open('get', 'demo.cgi');

r.setRequestHeader('X-Test', 'one');

r.setRequestHeader('X-Test', 'two');

r.send(null);

博客园 @ Dflying 版权所有 109/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

// ...would result in the following header being sent:

...

X-Test: one, two

...

The list of request headers MUST be reset when the open() method is called.

User agents MUST not set any headers other than the headers set by the author using this method,
with the following exceptions:

• UAs MUST set the Host header appropriately (see open()) and not allow it to be
overridden.
• UAs MUST set the Authorization header according to the values passed to the
open() method (but MUST allow calls to setRequestHeader() to append values to
it).
• UAs MAY set the Accept-Charset and Accept-Encoding headers and MUST
NOT allow them to be overridden.
• UAs MAY set the If-Modified-Since, If-None-Match, If-Range, and
Range headers if the resource is cached and has not expired (as allowed by HTTP),
and MUST NOT allow those headers to be overridden.
• UAs MUST set the Connection and Keep-Alive headers as described by the
HTTP specification, and MUST NOT allow those headers to be overridden.
• UAs SHOULD set the proxy-related headers according to proxy settings of the
environment, and MUST NOT allow those headers to be overridden.
• UAs MAY give the User-Agent header an initial value, but MUST allow authors to
append values to it.
• UAs SHOULD set Cookie and Cookie2 headers appropriately for the given URI and
given the user's current cookies, and MUST allow authors to append values to these
headers.

In particular, UAs MUST NOT automatically set the Cache-Control or Pragma


headers to defeat caching [RFC2616].

Parameters
header of type DOMString
@XXX TDB@
value of type DOMString
@XXX TDB@
No Return Value
Exceptions
DOMException UNKNOWN_ERR @XXX TDB@

博客园 @ Dflying 版权所有 110/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

HTTP requests sent from multiple different XMLHttpRequest objects in succession SHOULD be
pipelined into shared HTTP connections.

A. References

This section is normative

DOM3
Document Object Model (DOM) Level 3 Core Specification, Arnaud Le Hors (IBM), Philippe Le
Hégaret (W3C), Lauren Wood (SoftQuad, Inc.), Gavin Nicol (Inso EPS), Jonathan Robie
(Texcel Research and Software AG), Mike Champion (Arbortext and Software AG), and Steve
Byrne (JavaSoft).

RFC2119
Key words for use in RFCs to Indicate Requirement Levels, S. Bradner.

RFC2616
Hypertext Transfer Protocol -- HTTP/1.1, R. Fielding (UC Irvine), J. Gettys (Compaq/W3C), J.
Mogul (Compaq), H. Frystyk (W3C/MIT), L. Masinter (Xerox), P. Leach (Microsoft), and T.
Berners-Lee (W3C/MIT).

B. Authors

This section is informative

The authors of this document are the members of the W3C Web APIs Working Group.

• Robin Berjon, Expway (Working Group Chair)


• Ian Davis, Talis Information Limited
• Gorm Haug Eriksen, Opera Software
• Marc Hadley, Sun Microsystems
• Scott Hayman, Research In Motion
• Ian Hickson, Google
• Björn Höhrmann, Invited Expert
• Dean Jackson, W3C
• Christophe Jolif, ILOG
• Luca Mascaro, HTML Writers Guild
• Charles McCathieNevile, Opera Software
• T.V. Raman, Google
• Arun Ranganathan, AOL
• John Robinson, AOL
• Doug Schepers, Vectoreal
• Michael Shenfield, Research In Motion
• Jonas Sicking, Mozilla Foundation
• Stéphane Sire, IntuiLab

博客园 @ Dflying 版权所有 111/114


Atlas 学习指南 Dflying http://dflying.cnblgos.com

• Maciej Stachowiak, Apple Computer


• Anne van Kesteren, Opera Software

Thanks to all those who have helped to improve this specification by sending suggestions and
corrections. (Please, keep bugging us with your issues!)

博客园 @ Dflying 版权所有 112/114

You might also like