ASP.NET中DATAGRID常见错误
发布时间:2006-5-29 8:11:38   收集提供:shendata
DATAGRID 控件是 MICROSOFT ASP.NET 中功能最强、用途最广的 WEB 控件之一,这一点已经得到了 ASP.NET 权威人士的认同。虽然 DATAGRID 控件易于使用,但同样易于给使用者带来麻烦。以下是许多人所犯的一些错误,这些人包括从初学者到富有经验的 .NET 专家。您可以看到许多苦闷的使用者在 ASP.NET 新闻组和论坛就这些错误提出问题。遵循本文概述的相当简单的步骤,可以帮助您避免这些错误,并节约大量的开发时间。

  可以使用 DATAGRID 创建列表数据而没有使用

  我知道您不会再使用如下所示的代码,但 ASP.NET 领域中许多守旧的用户仍在继续使用它们:

RESPONSE.WRITE("<TABLE>")
WHILE MYDATAREADER.READ()
RESPONSE.WRITE("<TR>")
RESPONSE.WRITE("<TD>")
RESPONSE.WRITE(MYDATAREADER(0))
RESPONSE.WRITE("</TD>")
RESPONSE.WRITE("</TR>")
LOOP
RESPONSE.WRITE("</TABLE>") 

  可以对以上代码进行简化,使其仅为:

<ASP:DATAGRID RUNAT="SERVER" DATASOURCE="MYDATAREADER"/>

  并调用 .DATABIND() 方法。即使需要对HTML输出进行特殊的控制,您也可以在用户界面上记录集的内容重复出现的情况下,使用某个数据 WEB 控件。

  忘记在 PAGE_LOAD 事件中检查 ISPOSTBACK

  最常见的错误之一是忘记在数据绑定之前检查页面的 ISPOSTBACK 条件。例如,DATAGRID 处于“EDIT”(编辑)模式时,忽略该项检查将导致已编辑的值被数据源中的原始值覆盖。然而,该规则至少有一个主要的例外,请参阅持续使用大型 VIEWSTATE。

  以下是包含 ISPOSTBACK 检查的一个典型 PAGE_LOAD 事件。BINDGRID() 是一个例程,用于导入并设置 DATAGRID 的数据源,并调用 DATABIND() 方法。

SUB PAGE_LOAD
IF NOT ISPOSTBACK THEN
BINDGRID()
END IF
END SUB

  需要更大的灵活性时,仍坚持使用自动生成的列

  如果 DATAGRID 所处的环境需要任何一种特殊格式,或是需要使用 DATAGRID 中的其他任何 WEB 控件,那么必须关闭 AUTOGENERATECOLUMNS。将 AUTOGENERATECOLUMNS 属性的设置保持为“TRUE”(默认设置)的做法,仅在最简单的 DATAGRID 方案中有效。但对几乎所有实际的应用程序,必须将该属性设置为“FALSE”,并在 DATAGRID 声明的 <COLUMNS></COLUMNS> 段中明确地指定列。MICROSOFT VISUAL STUDIO .NET 用户可以使用属性生成器以图形化的方式创建这些列。

  注意:如果将 AUTOGENERATECOLUMNS 的设置保持为“TRUE”,并且在 DATAGRID 的 <COLUMNS> 段中指定了列,那么最终将得到对列的重复设置。系统将首先显示特别声明的列,随后是所有自动生成的列。

  尝试仅使用控件 ID 来引用 DATAGRID 项目中的控件

  许多人没有认识到,对于 DATAGRID 的 TEMPLATECOLUMN 下的 ITEMTEMPLATE 中的控件(例如带有“MYTEXTBOX”ID 的 TEXTBOX 控件),不能在后面的代码或是在 ASPX 页面的 <SCRIPT> 段中用如下所示的代码来直接调用该控件:

DIM MYVALUE AS STRING = MYTEXTBOX.TEXT

  该代码将导致可怕的“名称‘MYTEXTBOX’没有声明”错误。

  因为 DATAGRID 是由多个行(项目)组成的,所以数据源中的每一行实际都会有一个单独的“MYTEXTBOX”实例。ASP.NET 在每个控件的 ID 前面加上该控件层次结构中每个命名容器的 ID,这样 TEXTBOX 将具有唯一的 ID,与页面中所有其他控件的 ID 都不相同。例如,如果 MYTEXTBOX 处于 DATAGRID1 中,那么生成的 ID 将是 DATAGRID1:_CTL2:MYTEXTBOX。“_CTL2”代表 MYTEXTBOX 所处的当前行。页面中其他 MYTEXTBOX 实例的 ID 可能是 DATAGRID1:_CTL3:MYTEXTBOX、DATAGRID1:_CTL4:MYTEXTBOX 等等。要检索需要查找的“MYTEXTBOX”值,需要对适当的 DATAGRIDITEM 调用 FINDCONTROL 方法。该 DATAGRIDITEM 用作 TEXTBOX 的父命名容器。

  HTML:

<ASP:DATAGRID RUNAT="SERVER" ID="DATAGRID1">
<COLUMNS>
<ASP:TEMPLATECOLUMN>
<ITEMTEMPLATE>
<ASP:TEXTBOX RUNAT="SERVER" ID="MYTEXTBOX"/>
</ITEMTEMPLATE>
</ASP:TEMPLATECOLUMN>
</COLUMNS>

  代码:

SUB DATAGRID1_UPDATECOMMAND(SENDER AS OBJECT, E AS DATAGRIDCOMMANDEVENTARGS)
 DIM MYVALUE AS STRING = CTYPE(E.ITEM.FINDCONTROL("MYTEXTBOX"), TEXTBOX).TEXT
 '对 MYVALUE 执行操作
END SUB

  对 FINDCONTROL 调用的结果调用 CTYPE,将会把返回值由 OBJECT 类型强制转换成 TEXTBOX 类型,以访问 .TEXT 属性。

  忘记在每个 DATAGRID 事件中执行 .DATABIND() 调用,从而导致回发

  一个常见的问题是:“当我点击 DATAGRID 某一行中的 EDIT(编辑)链接时,页面回发,且不包含任何数据。这是什么错误?”问题在于数据仅在页面第一次被调用时绑定到网格。在每个 DATAGRID 事件(EDIT、UPDATE、CANCEL、PAGE 或 SORT)中,请确保设置了 DATAGRID 的 DATASOURCE 属性(除非已经在 <ASP:DATAGRID> 声明中通过声明的方式进行了设置),并对 DATAGRID 调用了 DATABIND() 方法。

  运行时不必要地在 DATAGRID 中动态创建 DATAGRID 控件或列

  在某些业务和技术方案中,在运行时创建 ASP.NET 控件是必要的,也是完全合适的。例如,有时需要在选择其他页面选项后,才能在运行时确定用户界面。或是要创建一个复合服务器控件,其中的每个子控件都需要动态创建,因为无法以声明的方式创建这些子控件。如果遇到这些情况,请注意,提交页面时不要保留这些动态控件。必须在页面生命周期的早期,在每次回发时重新创建动态控件(例如在 PAGE_INIT 事件中)。警言:创建控件要早,创建控件要勤。有关如何动态创建控件的详细信息,请参阅 MICROSOFT KNOWLEDGE BASE 文章 HOW TO:DYNAMICALLY CREATE CONTROLS IN ASP.NET WITH VISUAL BASIC .NET。

  然而,如果 DATAGRID 应用程序中不是一定需要动态创建控件,请避免使用该技术,以免遇到麻烦。尽管可能创建动态 DATAGRID,但它们会引发各种事件,这通常都会令人头疼。换句话说,不要动态创建控件,以避免因为创建控件使 ASPX 文件变得散乱。

  持续使用大型 VIEWSTATE

  DATAGRID 控件会在页面中添加大量的 VIEWSTATE,这一点令人讨厌,因为这会导致呈现给用户的页面的总体大小急剧增加。要使页面大小不增加,最简单的方法是无论对整个页面,还是单独对某些特定的控件,都禁用 VIEWSTATE。例如,如果页面不产生回发,那么对整个页面禁用 VIEWSTATE 是安全的。否则,请对两次回发之间状态信息不会发生更改的各个控件禁用 VIEWSTATE,或者对不需要隐藏字段来跟踪自身状态的那些控件禁用 VIEWSTATE。

  对 DATAGRID 控件或包含 DATAGRID 的页面禁用 VIEWSTATE 时,如果 DATAGRID 会启动回发事件,那么需要执行一些特殊的步骤。首先,必须在每次回发时在 PAGE_LOAD 中重新绑定 DATAGRID。这有违常规做法(以及上述第二个问题中的描述)。但如果禁用 VIEWSTATE,该步骤是必需的,这样在执行 PAGE_LOAD 后可以正确地引发其他 DATAGRID 事件。如果要处理以下 DATAGRID 事件中的任何一部分(或全部),那么还需要在 VIEWSTATE 中手动存储一些 DATAGRID 属性。例如,在禁用了 VIEWSTATE 的 DATAGRID 中进行编辑时,只要是在 PAGE_LOAD 中第一次绑定 DATAGRID 之前重新存储 EDITITEMINDEX,且 DATAGRID 处于编辑模式,那么只需将 EDITITEMINDEX 储存到 VIEWSTATE 就够了。

  表 1:DATAGRID 事件与 VIEWSTATE 的依赖关系
事件 是否依赖于 VIEWSTATE? 要存储在 VIEWSTATE 中的字段
ITEMCREATED  
ITEMDATABOUND  
SORTCOMMAND SORTEXPRESSION
EDITCOMMAND EDITITEMINDEX
PAGEINDEXCHANGED CURRENTPAGEINDEX
SELECTEDINDEXCHANGED  

  清单 1:启用编辑、排序和分页,但禁用 VIEWSTATE 的 DATAGRID 的示例代码。

SUB PAGE_LOAD
 IF NOT VIEWSTATE("EDITITEMINDEX") IS NOTHING THEN
  DATAGRID1.EDITITEMINDEX = VIEWSTATE("EDITITEMINDEX")
 END IF
 IF NOT VIEWSTATE("CURRENTPAGEINDEX") IS NOTHING THEN
  DATAGRID1.CURRENTPAGEINDEX = VIEWSTATE("CURRENTPAGEINDEX")
 END IF
 BINDGRID()
END SUB

SUB BINDGRID()
 DIM DV AS DATAVIEW
 DV = GETDATASOURCE()
 DV.SORT = VIEWSTATE("SORTEXPRESSION")
 DATAGRID1.DATASOURCE = DV
 DATAGRID1.DATABIND()
END SUB

SUB DATAGRID1_SORTCOMMAND(S AS OBJECT, E AS DATAGRIDSORTCOMMANDEVENTARGS)
 VIEWSTATE("SORTEXPRESSION") = E.SORTEXPRESSION
 BINDGRID()
END SUB

SUB DATAGRID1_EDITCOMMAND(S AS OBJECT, E AS DATAGRIDCOMMANDEVENTARGS)
 DATAGRID1.EDITITEMINDEX = E.ITEM.ITEMINDEX
 VIEWSTATE("EDITITEMINDEX") = E.ITEM.ITEMINDEX
 BINDGRID()
END SUB

SUB DATAGRID1_PAGEINDEXCHANGED(S AS OBJECT, E AS DATAGRIDPAGECHANGEDEVENTARGS)
 DATAGRID1.CURRENTPAGEINDEX = E.NEWPAGEINDEX
 VIEWSTATE("CURRENTPAGEINDEX") = E.NEWPAGEINDEX
 BINDGRID()
END SUB

  使用 ITEMDATABOUND 或 ITEMCREATED 事件时,忘记检查适当的 LISTITEMTYPE

  DATAGRID 控件对每个数据行引发两个事件。首次将每行添加到 DATAGRID 时将引发 ITEMCREATED 事件,将数据绑定到每行时将引发 ITEMDATABOUND 事件。添加单元格到 DATAGRID 的表格输出时,这些事件可以用于控制每个单元格的外观或内容。例如,可以基于数值的范围修改单元格的背景颜色。但关键是要记住,这些事件的引发针对的是所有 DATAGRID 项目类型,包括页眉、页脚和分页程序项目。如果执行 ITEMDATABOUND 事件期间,没有在引用项目的数据之前仔细检查项目类型,第一个项目(通常是标题行)就将发生错误。如果 DATAGRID 启用了分页,且将其设置为在顶端显示,那么第一个项目就会成为分页程序项目。以下示例代码显示如何在引用项目数据之前进行正确的 LISTITEMTYPE 检查。不要忘了 ALTERNATINGITEM!

SUB DATAGRID1_ITEMDATABOUND(SOURCE AS OBJECT,E AS DATAGRIDITEMEVENTARGS)
IF (E.ITEM.ITEMTYPE = LISTITEMTYPE.ITEM OR E.ITEM.ITEMTYPE = LISTITEMTYPE.ALTERNATINGITEM)   THEN
  IF E.ITEM.DATAITEM("FORUMDATE") < DATETIME.TODAY THEN
    E.ITEM.CELLS(1).BACKCOLOR =SYSTEM.DRAWING.COLOR.FROMNAME("#FFCCFF")
  END IF
 END IF
END SUB


  需要对生成的 HTML 有更多的控制时,过多地使用了 DATAGRID(REPEATER 也许是更好的选择)

  如果懒散的程序员喜欢 DATAGRID 控件(因为 DATAGRID 控件为他们完成了很多工作),那么有着极强控制欲的程序员必定喜欢 REPEATER 控件。如果需要或希望完全控制创建的所有 HTML,请使用 REPEATER 控件,它能帮助您完成该任务。REPEATER 控件在性能上也略占优势,因为它不像 DATAGRID 控件的所有内置功能那样占用系统资源。也可以考虑使用折衷的 DATALIST 控件,它具备编辑和排序功能,同时还具有在一行内重复显示记录的功能。

 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50