datagrid基础篇

浩子 2003-3-18 13:06:39

在项目实际应用中,常用datagrid控件,datagrid控件非常好用,今天我们来讲讲datagrid的基本的原理和概念性的东西,然后在续篇中我们会介绍datagrid的一些实用技巧。

首先我们来看一下datagrid的组成,我们可以把datagrid理解成是html里面的一个table,table是由行(tr)和列(td)组成,而datagrid的行其实是datagriditem对象,而列就是datagridcolumn 对象。在datagrid对象的属性集了我们可以看到items和columns 属性,它们分别就是datagrid的行集和列集,也就是datagriditem对象集合及datagridcolumn 对象集合。通过查看asp.net生成的html页的源代码,我们也可以发现,datagrid的表现形式也就是table。

我们也可以把datagrid理解成数据库里面的表,也是由行和列组成。就像我们建数据库表一样,我们首先要构造表的列,在创建一个datagrid对象时,我们也是要先创建datagrid的列。Datagrid的列有以下几种类型:BoundColumn(绑定列)、ButtonColumn(按钮列)、EditCommandColumn(编辑命令列)、HyperLinkColumn(超链接列)、TemplateColumn(模板列)。每种类型列实现的功能不一样,这里不一一细说了,大家可以在msdn查:ms-help://MS.VSCC/MS.MSDNVS.2052/cpref/html/frlrfSystemWebUIWebControlsDataGridClassTopic.htm

说完了datagridcolumn对象,我们再来看看datagriditem对象的类型,datagriditem有以下七种类型(它们组成ListItemType枚举类型的七种类型,不包含Separator,Separator一般用于datalist和repeater控件分隔行,不能绑定数据):Header(标题行)/Item(正常数据绑定行)/AlternatingItem(数据绑定分隔行)/footer(脚注行)/edititem(编辑行)/Pager(分页导航行)/SelectedItem(选中行),通过datagriditem的itemtype属性,我们可以知道某个datagriditem对象是哪一种类型,从而进行不同的处理。这在我们定制多表头及分页导航栏等一些情况下非常有用,后续篇我们会讲到这些应用。

然后我们看看datagrid支持的一些常用的事件,它们在什么条件下触发?它们执行的顺序是什么?它们会触发时改变了哪些属性和对象?这些问题对编辑人员来说是非常重要的。也是我们用好datagrid 的基础,下面我们分别讲述DataBinding、itemcommand、itemcreated、itemdatabound这几个事件。

因为datagrid是以列的形式来呈现(表现)数据的,一般情况下我们在声明一个datagrid的时候,就指定了datagrid要显示的列,所以datagrid的创建工作就只是创建行的工作了。当我们设置了datagrid的datasource属性,就调用datagrid的databind()方法,把数据源绑定到datagrid上,这时就触发了databinding事件。因为我们使用datagrid主要就是和数据打交道,我们可以把databinding事件看作是创建datagrid 的入口,也就是datagrid的创建工作是由databinding事件开始,它是创建datagrid最先执行的事件。接着,datagrid根据数据源开始创建行的工作。

通过监视,我们发现datagird按如下顺序创建行(假设我们先把datagird 的allowpaging属性设为 true):PageràHeaderàItemà AlternatingItemàItemà AlternatingItemà Itemà……(直至创建完所有内容行)àFooteràPager ;如果我们把datagird 的allowpaging属性设为 false;,datagird则按如下顺序创建行: HeaderàItemà AlternatingItemàItemà AlternatingItemà Itemà……(直至创建完所有内容行)àFooter ;如果我们是按下了edit button(或select button) ,datagrid首先要取得edititem或selecteditem的itemindex,然后在创建行的过程中,与正在创建行的itemindex属性比较,如果相等,则这一行按照edititemtemplate或selecteditemtemplate规定的模板创建,那么datagrid按如下顺序创建行:HeaderàItemà AlternatingItemàItemà AlternatingItemà Itemà…àedititem(selecteditem)à…(直至创建完所有内容行)àFooter 。值得注意的是,当我们把datagird 的allowpageing属性设为 true时,最先创建是的是分页导航行(Pager),而且在最后又重新创建了一次于分页导航行(Pager),首先创建pager行,可以理解为datagrid必须先依据Pager行才能知道现在要显示第几页,才好做下面的创建工作。但在最后又重新创建Pager行的原因是什么呢?还是请各位高手解答,我是没有搞清楚为什么要这样做?。另外我们要注意的是,即使我们没有设置datagrid 的AlternatingItemStyle样式,在创建行时,datagrid也是按照itemà AlternatingItem的顺序创建,只不过它把ItemStyle样式应用在AlternatingItem(分隔行)上。并不是datagrid不创建AlternatingItem行,我在开始用datagrid的时候就是这样认为。

创建行时首先触发itemcreated事件,每创建完上面的任何一行,都会触发itemcreated事件,通过itemcreated事件,我们可以定制datagird的任何类型的行。我们常在该事件中定制header(标题行),pager(分页导航行),及footer(脚注行),后续篇会我们讲到。执行完itemcreated事件后,一行的框架就打出来了,无需数据绑定的列都已完全建好了。接着要对需要进行数据绑定的列进行数据绑定,也就是把数据源的值赋到各个列中,也包括执行aspx页面的数据绑定表达式,就是像这种代码:<%# 表达式 %>。完成数据绑定后,这时就触发了itemdatabound事件,在itemdatabound事件里,提供了我们访问datagrid的数据源的最后的机会,在itemcreated和itemdatabound事件里,我们可以通过(DataRowView)(e.Item .DataItem),把e.Item..DataItem强制转换成DataRowView对象,然后我们就可以访问该数据源了。根据数据源中的数据,我们可以定制或改变datagrid某行或某列的显示值或显示样式。但要注意以下两点:一是创建pager行时并不会触发itemdatabound事件,因为pager行不进行数据绑定。二是只有在创建item行、AlternatingItem行、selecteditem行、edititem行时e.Item.DataItem才有值;创建其它类型的行时,e.Item.DataItem的值都为null。所以我们在处理e.Item.DataItem时必须先判断e.Item.itemtype属性为上述类型行时,才能取出数据源的值;否则会抛出“对象不能为null“的异常。

执行完itemdatabound事件后,一行的创建工作就完成了。这时我们发现datagrid的items.count属性的值加了一,表示这一行创建完毕,加入了datagrid.items集合中。

Datagrid循环地调用itemcreated和itemdatabound事件创建完所有的行后,就完成了datarid的创建工作。也就是说,执行完databinding事件后(itemcreated和itemdatabound是嵌套在databinding事件里执行的),整个datagrid就创建完了。如果我们要在这以后再访问datagrid里面的数据或内容,就只有通过datagird的items集合访问行数据,再通过datagirditem的cells集合访问datagrid的列数据或控件。如果此时你想通过datagirditem.dataitem属性访问datagrid的数据源,就会抛出”找不到对象或对象为null”的异常。因为在执行完itemdatabound事件后datagriditem.dataitem属性已经被置为null了。

最后我们说说itemcommand事件,如果我们在datagrid的列模板中设置了buttoncolumn列或者说在itemtemplate中放置了linkbutton控件、checkbox控件、button控件等;所有这些控件引起页面提交时,都会触发datagrid的itemcommand事件,它们并不会触发它们本身的事件,例如button的click事件等。这种事件机制在asp.net里面称之为“冒泡事件“,在msdn上冒泡事件是这样解释的:不同于每个按钮单独引发一个事件,来自嵌套控件(这些控件放在datagrid容器中)的事件是“冒泡的”——也就是说,这些事件都将发送到容器中。该容器又引发一个带有参数的一般事件,名为 ItemCommand,它的参数使您可以发现是哪个控件引发了该事件。通过响应此单个事件(指只响应ItemCommand事件),可以避免不必要地为子控件编写单独的事件处理程序。关于“冒泡事件”请参考msdn:ms-help://MS.NETFrameworkSDK.CHS/cpguidenf/html/cpconwebformseventmodel.htm。

Contributors: FHL