当前位置:首页>>开发编程>>VS.NET>>新闻内容
ASP.NET中Datagrid常见错误
作者:MS 发布时间:2004-9-23 15:06:06 文章来源:西部E网
  摘要:学习如何避免在使用 ASP.NET Datagrid 控件进行开发时可能发生的一些常见错误。

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

  1、可以使用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 控件。

  2、忘记在Page_Load事件中检查IsPostBack

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

  以下是包含 IsPostBack 检查的一个典型 Page_Load 事件。BindGrid() 是一个例程,用于导入并设置 Datagrid 的数据源,并调用 DataBind() 方法。

//VB.NET
Sub Page_Load
If Not IsPostBack Then
BindGrid()
End If
End Sub

//C#
private void Page_Load(object sender, System.EventArgs e)
{
 if(!Page.IsPostBack)
 {
  BindData();
 }
}

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

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

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

  4、尝试仅使用控件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 属性。

  5、忘记在每个Datagrid事件中执行 .DataBind() 调用,从而导致回发

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

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

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

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

  7、持续使用大型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

  8、使用 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

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

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


最新更新
·C#中使用Split分隔字符串的技
·VS2008开发中Windows Mobile
·PC机和移动设备上绝对路径的
·C#程序加壳的方法(使用Sixx
·当前上下文中不存在名称Conf
·请插入磁盘:Visual Studio 2
·用VS.NET读取Flash格式文件信
·在ASP.NET中使用AJAX的简单方
·VS.NET 2005中常用的一些代码
·安装VS.NET 2005 SP1补丁全攻
相关信息
画心
愚爱
偏爱
火苗
白狐
画沙
犯错
歌曲
传奇
稻香
小酒窝
狮子座
小情歌
全是爱
棉花糖
海豚音
我相信
甩葱歌
这叫爱
shero
走天涯
琉璃月
Nobody
我爱他
套马杆
爱是你我
最后一次
少女时代
灰色头像
断桥残雪
美了美了
狼的诱惑
我很快乐
星月神话
心痛2009
爱丫爱丫
半城烟沙
旗开得胜
郎的诱惑
爱情买卖
2010等你来
我叫小沈阳
i miss you
姑娘我爱你
我们都一样
其实很寂寞
我爱雨夜花
变心的玫瑰
犀利哥之歌
你是我的眼
你是我的OK绷
贝多芬的悲伤
哥只是个传说
丢了幸福的猪
找个人来爱我
要嫁就嫁灰太狼
如果这就是爱情
我们没有在一起
寂寞在唱什么歌
斯琴高丽的伤心
别在我离开之前离开
不是因为寂寞才想你
爱上你等于爱上了错
在心里从此永远有个你
一个人的寂寞两个人的错