[概述]
web开发自从有了基于脚本的web编程技术(如asp)以来,经历了一个漫长的过程。通过使用微软的asp.net技术,传统的asp中大量的、单调乏味的、重复性的编程工作成为了历史。例如,象大多数asp程序员所知的,在asp中显示数据库内容所需要的过程:
建立数据库连接
用sql查询装载ado数据集
显示所需要的任何html代码
遍历数据集中的记录
输出记录字段值及相关的html
移向下一条记录
循环
显示所需要的html代码
又如,为了在表格中显示记录集的内容,我们需要输出一个<table>标签,然后开始循环。在循环中,每输出一条记录,需要先输出一个<tr>标签以及若干对<td>标签和</tr>标签。最后,以一个</table>标签结尾。
在传统的asp中使用的这种方法有一个主要的缺点:html代码与asp源代码不得不纠缠在一起。对于那些也许并不理解程序设计的页面设计者或图形艺术家来说,想要更改html内容无疑是一场灾难。另外,代码的产生量也是惊人的,因为我们不仅需要从数据库中取得数据,还需要使之可视化。
好在,asp.net提供了三个数据控件,使得原本在asp中繁杂的工作变得简单。这三个控件属于数据web控件,分别是datagrid,datalist和repeater。如果你对asp.net数据库编程有所了解的话,你至少应该有使用其中一种控件的经验。大多数情况下,我们从学习使用datagrid开始,因为它的功能相对完整(数据显示、分页、编辑)并相对简单。然而,datagrid并非总是正确的选择。
本文将分别论述每个数据控件不同于其它数据控件的特点,以及由此带来的优缺点。正因为每种数据控件都有其自身的缺陷,因此在程序设计中并不存在最完美的选择。你必须权衡三种控件的优缺点并决定哪一种更加适合你的程序。
为了帮助比较,在对每个控件进行论述时,我们会专注于三个特性:可用性(从页面访问者的角度)、开发时间和性能。我们首先描述一下这三种控件的共性,然后分别深入地讨论三种控件的特点,每种控件如何实现以及如何体现可用性、开发时间和性能。
[数据控件(data web controls)的共同点]
在我们讨论三种控件各自特性之前,有必要先看一看它们之间的共同点。一般来说,从编程流程来看,最显著的共同点就是,这三种控件都是用来显示数据的。另一个共同点是需要一个数据绑定的代码来将数据与控件绑定。这个过程只需要两行代码:
datawebcontrolid.datasource = somedatasource
datawebcontrolid.databind()
一般情况下,somedatasource对象是指数据控件的数据源属性,可以是dataset,sqldatareader,oledbdatareader或一组数据(如数组、数组列表或其它的属于system.collection名空间的类)。不过,任意实现ienumerable接口的对象也可以被绑定在数据控件上。
databind()方法遍历一个特定的datasource中的记录,并对其中的每条记录,建立一个条目并对应数据控件的item集。数据控件中的每个条目将成为一个类的实例。这个类因数据控件的不同而有所区别。例如,datagrid中的每个条目是datagriditem类的一个实例,而repeater中的条目则是repeateritem类的一个实例。
之所以使用不同的类来实例化不同数据控件的条目,是因为不同的数据控件将会使用不同的方式显示数据及相应的html代码。例如,datagriditem类继承自tablerow类,也就是说,每个datagriditem的实例或多或少地可以看成一个表格中的一行。这是因为datagrid被设计成可以借助html中的<table>标签以表格的形式显示数据,因此每条记录就是一个表格行。而repeater则被设计成可以自由定义数据输出的方式。所以,repeateritem并不继承自tablerow就不奇怪了。
另一个三种数据控件的相同点是每种控件都被允许使用模板来显示数据。datalist和repeater控件必须使用模板来输出数据,而datagrid则允许通过templatecolumn而只使用模板来显示一列(在datagrod单元中详细论述)。
另一个不是十分值得比较的地方是:datagrid和datalist都是继承自webcontrol类,而repeater则是继承自control类。webcontrol类包含一些用于美化的属性,如:backcolor、forecolor、cssclass、borderstyle等等。这说明在使用datagrid或datalist时,你可以设定这些属性来个性化输出。repeater控件则不具有这些属性。我们会在repeater单元讨论如何使用模板来美化repeater的输出。
[datagrid控件]
在三种控件当中,datagrid是迄今为止功能最为丰富的,但也是最不灵活的控件。这种在输出html时不够灵活的特点是因为它最初就是被设计成以表格的形式输出数据。每一条记录输出时会建立一对<tr>标签,而每个字段的值输出时则建立一对<td>标签。
datagrid含有几个属性可以提高其可用性。如,通过设置datagrid的allowsorting属性为true,并加入少量代码,datagrid就具备了按不同字段排序的功能。此外,设定相关属性来实现分页以及单条记录编辑的功能更加增强了datagrid的可用性。
除了在可用性方面的支持以外,datagrid同时也相当节省开发时间。使用datagrid在web页面上显示数据只需要两行代码。一行用来设定与datagrid绑定的数据源(datasource),另一条则用来执行绑定命令(databind())。当然,在repeater中实现这样的功能并非不可能,只是,相比较使用datagrid而言,你需要花费相当多的时间和精力来实现这些功能。
尽管datagrid有这样那样令人印象深刻的优点,它的两个缺点也同样不能忽视。首先,如前所述,datagrid在个性化输出数据方面功能有限。当然,你可以定制字体、颜色以及线条宽度等等,但它始终只能是html表格。
每个在datagrid中的列都是datagridcolumn类的一个实例。有五种datagrid列的形式:
·boundcolumn
·buttoncolumn
·editcolumn
·hyperlinkcolumn
·templatecolumn
每种类型都会以一种方式允许页面访问与datagrid进行交互。例如,boundcolumn将datasource的字段值显示为纯文本;而hyperlinkcolumn则将之显示为一个超级链接。另外,开发者可以通过写一个继承自datagridcolumn的自定义类来定制datagrid列的样式。
尽管datagrid具有这么多的增强可用性的属性,却仍然显得死板而不够灵活。这是因为,不论什么样的属性,都需要对datagrid所生成的表格进行相关的设置而生效。这无疑会使表格变得臃肿而失去灵活性。例如,datagridcolumn的设置会对表格的每一行的相应列生效。datagrid的这种局限性阻碍了更有创意地显示数据。比如,你希望每五条记录被显示在一行,或根本不想要表格来显示数据,你将不得不放弃使用datagrid。
datagrid的第二个缺陷是它的性能。在三种数据控件中,datagrid是相对性能最差的。由datagrid所生成的viewstate将会相当庞大,特别是在datagrid含有较多的行时。当然,你也可以关闭viewstate功能,但代价是你将不能使用排序、分页以及记录编辑等功能。
为了测量datagrid的性能,我使用了微软的web application stress tool (wast)。精确的测试条件设定以及测试用代码将会在本文的结尾给出。
wast将会对web服务器发出对一个特定url的请求。每个测试将会针对一个url在一分钟之内连续不断地请求。wast将会一个代表性能的数值,代表web服务器将会在一秒钟内执行asp.net页面多少次。
两个测试将显示一个仅仅显示数据的datagrid。datagrid将会显示northwinds数据库中的customers表的4个字段的内容(总计91条记录)。datagrid的autogeneratecolumns属性将会被设为true。第一个测试将datagrid置于一个form中,第二个则不置于form中。将控件置于form中而不指定其enableviewstate为false,则控件将会一直使用viewstate来维持其状态。对viewstate的设定是为了有一个耗时的处理过程,来看一下它对于每秒种的页面请求有什么样的影响。测试结果见图1。
图1:对datagrid的每秒请求次数
在下面我们要讨论并测试的datalist和repeater中,我们会看到它们的性能将优于datagrid。
[datalist控件]
如前所述,datagrid使用表格来显示数据。你也许需要更进一步地控制数据的显示。例如,你想使数据在表格中显示,但不是每行只有一条记录,而是多条。又或者,你并不想使用表格来显示数据,而是只将它们显示在一系列<span>标签中。
datalist放弃了datagrid中列表显示数据的概念,而是使用事先定义好的模板(template)来定制显示。通过使用模板,可以同时使用html标签或数据绑定。这里的数据绑定的形式为:<%# … %>,用来显示数据源中给定条目的数据记录。如下的itemtemplate将会显示数据源中companyname字段:
<asp:datalist runat="server" id="mydatalist">
<itemtemplate>
<%# databinder.eval(container.dataitem, "companyname") %>
</itemtemplate>
</asp:datalist>
通过修改上面的模板,我们可以使companyname字段显示为粗体字,而contactname字段则以正常式样显示在companyname之下。
<asp:datalist runat="server" id="mydatalist">
<itemtemplate>
<b><%# databinder.eval(container.dataitem, "companyname") %></b>
<br />
<%# databinder.eval(container.dataitem, "contactname") %>
</itemtemplate>
</asp:datalist>
对于datalist数据源中的每一条记录,itemtemplate会通过定义html标签来以相同的样式显示数据。itemtemplate还支持其它其它6种模板:
·alternatingitemtemplate
·edititemtemplate
·footertemplate
·headertemplate
·itemtemplate
·selecteditemtemplate
·separatortemplate
默认情况下datalist会将记录显示在html表格中。然而,通过设定repeatcolumn属性,你可以设置在一行中显示多少条记录。更进一步,你甚至可以指定datlist的内容不显示在表格中,而是<span>标签中。这可以通过设定repearlayout属性来实现。
通过模板、repeatcolumn和repeatlayout属性,很明显datalist在定制数据输出样式方面较datagrid更具灵活性,使得用户界面设计可以更加友好。当然,我们还需要进行功能性的对比,如分页、排序、记录编辑等等。
通过edititemindex模板和editcommand,updatecommand以及cancelcommand事件,datalist将支持记录编辑的功能。不过,比较datagrid而言,这需要耗费更多的开发时间来实现。这种开发时间上的不一致主要有两个原因:
·编辑/更新/删除按钮在datagrid中可以通过设定editcommandcolumn来自动添加;而在datalist中则需要手动添加。
·datagrid的boundcolumn列样式自动使用文本框控件来显示记录编辑界面。而在datalist中,你必须通过edititemtemplate明确地指定使用什么样的编辑界面。
实现datalist中的分页、排序功能同记录编辑功能情况一样,并不算非常复杂。这些功能可以通过巧妙的编程加以实现,只是耗费一些开发时间。所以,如果需要用户对数据记录进行排序或编辑的话,使用datagrid要比使用datalist方便得多。
datalist的性能要比datagrid好一些,特别是当datalist被包含在form当中时。图2显示了wast对datalist的测试。
图2:对datalist的每秒请求次数
可以看出,在被web form包含的情况下,datalist的性能要明显好于datagrid。
[repeater控件]
repeater控件是三种数据控件中在html输出方面最为灵活的控件。repeater会按照你所要求的样式严格地输出数据记录。所以,如果你不想以表格方式或者简单的<span>输出数据,那么最好使用repeater。
与datalist一样,repeater使用模板来指定输出样式。repeater支持如下五种模板:
·alternatingitemtemplate
·footertemplate
·headertemplate
·itemtemplate
·separatortemplate
hedertemplate和footertemplate指定在真正的记录输出之前或之后应处理的html内容。alternatingitemtemplate和itemtemplate则指定实际的每条输出记录的html样式。如,你需要绑定一个包含雇员信息的dataset到一个repeater,字段名为employeename。如果你想在页面中不排序地显示这些记录,你可以使用如下的语句:
<asp:repeater runat="server" id="rptemployees">
<headertemplate>
<ul>
</headertemplate>
<itemtemplate>
<li><%# databinder.eval(container.dataitem, "employeename") %></li>
</itemtemplate>
<footertemplate>
</ul>
</footertemplate>
</asp:repeater>
repeater类不是继承自webcontrol类的,这一点与datagrid和datalist不同。所以,repeater没有样式方面的属性可供设定。也就是说,如果你想格式化输出repeater的数据记录,你必须使用html标签来设定样式。如,在一例中,如果我们想将雇员名字显示成粗体,我们必须在itemtemplate设置相应的html标签:
<itemtemplate>
<li><b><%# databinder.eval(container.dataitem, "employeename")%></b></li>
</itemtemplate>
而如果使用datagrid或datalist,我们只通过设定itemstyle-font-bold属性为true即可实现。
repeater在格式化设定上的欠缺,直接反映到开发时间的延长上来。对输出数据样式上的越多要求,就越会导致开发周期的延长。这些在模板中规定样式的html标签也越发得显得混乱,而且,在将来页面更改时会更加困难,特别是当一个新的开发人员接替工作时。而使用datagrid或datalist你尽可以只设定样式属性,而不使用模板。而且,如果使用visual studio.net或asp.net web matrix工作时,这些属性更可以被直接设定而无需编码。
因为repeater开发时间的延长,其在内建功能(分页、排序及编辑)上的支持也显得不足。因此在可用性方面,repeater有着明显的缺陷。当然,<b>如果</b>用户对于如何显示数据无所谓的话,这也算不了什么大问题。我之所以强调这个“如果”,是因为尽管用户有时在设计时并不要求能够分页、排序或编辑记录,但这样的要求往往会在开发后期,或在他们能看到显示出来的记录后产生。
repeater唯一优于datagrid和datalist的特点是它的性能,尤其明显优于datagrid。而比datalist略高一点点。
[结论]
在asp.net页面上显示数据时,多数的程序员会选择他们所熟悉的控件来使用,特别是datagrid。然而,这样盲目的选择在没有“最好的通用控件”的情况下是不明智的。在选择控件来显示数据前,不妨问自己几个问题来帮助决策:是否允许用户对记录排序?是不是记录需要显示在非表格的情况下?页面是否会被高频度地访问,因此应多考虑性能?
datagrid提供了最多的功能,如允许访问者对记录编辑、排序或分页。同时它也是最容易使用的,甚至于简单到只需要将之添加到页面中而不必额外编写代码。不过这些易用性是以性能的损失为代价的。datagrid在三种控件中是效率最低的,特别是在使用web form的情况下。
通过使用模板,datalist提供了比datagrid更加优秀的界面效果。不过这需要以牺牲一定的开发时间为代价。为了添加排序、分页和编辑功能,程序员不得不花费比使用datagrid更多的精力来进行编码,虽然它的性能要优于datagrid。
最后,repeater允许对数据记录作最大限度的html定制。通常,使用repeater来显示数据记录比使用datagrid和datalist要耗费更长的开发时间。另外,它不支持内建的编辑、排序和分页功能。所幸的是,repeater在性能上要优于其它两种控件,特别是明显优于datagrid。
[附录]
wast测试设定
测试是在运行microsoft windows 2003 server操作系统的笔记本电脑上完成的。基本配置如下:intel p4 2.4g cpu;512 mb ram;30gb ultra ata hard drive;网页服务器使用iis 6.0;asp.net版本为1.1。此测试中的wast被设置成使用单线程,每个测试时间为一分钟。
测试代码http://download.microsoft.com/download/9/e/9/9e97b2f8-b317-4751-9ac1-2e34eebec26a/datacontrolsperftest_setup.msi点击此处下载
