摘要学习如何避免在使用 ASPNET Datagrid 控件进行开发时可能发生的一些常见错误(本文包含一些指向英文站点的链接) 目录 可以使用 Datagrid 创建列表数据而没有使用 忘记在 Page_Load 事件中检查 IsPostBack 需要更大的灵活性时仍坚持使用自动生成的列 尝试仅使用控件 ID 来引用 Datagrid 项目中的控件 可以(或应该)使用分页而没有使用 忘记在每个 Datagrid 事件中执行 DataBind() 调用从而导致回发 运行时不必要地在 Datagrid 中动态创建 Datagrid 控件或列 持续使用大型 ViewState 使用 ItemDataBound 或 ItemCreated 事件时忘记检查适当的 ListItemType 需要对生成的 HTML 有更多的控制时过多地使用了 Datagrid(Repeater 也许是更好的选择) 参考资料 datagrid 控件是 Microsoft® ASPNET 中功能最强用途最广的 Web 控件之一这一点已经得到了 ASPNET 权威人士的认同虽然 Datagrid 控件易于使用但同样易于给使用者带来麻烦以下是许多人所犯的一些错误这些人包括从初学者到富有经验的 NET 专家您可以看到许多苦闷的使用者在 ASPNET 新闻组和论坛就这些错误提出问题遵循本文概述的相当简单的步骤可以帮助您避免这些错误并节约大量的开发时间 可以使用 Datagrid 创建列表数据而没有使用 我知道您不会再使用如下所示的代码但 ASPNET 领域中许多守旧的用户仍在继续使用它们 ResponseWrite(<table>)While MyDataReaderRead()ResponseWrite(<tr>)ResponseWrite(<td>)ResponseWrite(MyDataReader())ResponseWrite(</td>)ResponseWrite(</tr>)LoopResponseWrite(</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 IfEnd 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 中的控件(例如带有MyTextBoxID 的 TextBox 控件)不能在后面的代码或是在 ASPX 页面的 <script> 段中用如下所示的代码来直接调用该控件 Dim MyValue As String = MyTextBoxText 该代码将导致可怕的名称MyTextBox没有声明错误 因为 Datagrid 是由多个行(项目)组成的所以数据源中的每一行实际都会有一个单独的MyTextBox实例ASPNET 在每个控件的 ID 前面加上该控件层次结构中每个命名容器的 ID这样 Textbox 将具有唯一的 ID与页面中所有其他控件的 ID 都不相同例如如果 MyTextBox 处于 DataGrid 中那么生成的 ID 将是 DataGrid:_ctl:MyTextBox_ctl代表 MyTextBox 所处的当前行页面中其他 MyTextBox 实例的 ID 可能是 DataGrid:_ctl:MyTextBoxDataGrid:_ctl:MyTextBox 等等要检索需要查找的MyTextBox值需要对适当的 DataGridItem 调用 findcontrol 方法该 DataGridItem 用作 TextBox 的父命名容器 html <asp:Datagrid runat=server id=Datagrid><Columns><asp:TemplateColumn><ItemTemplate><asp:TextBox runat=server id=MyTextBox/></ItemTemplate></asp:TemplateColumn></Columns> 代码 Sub DataGrid_UpdateCommand(sender As Object _ e As DataGridCommandEventArgs) Dim MyValue As String = _ CType(eItemFindControl(MyTextBox) TextBox)Text 对 MyValue 执行操作End Sub 对 FindControl 调用的结果调用 CType将会把返回值由 Object 类型强制转换成 TextBox 类型以访问 Text 属性 可以(或应该)使用分页而没有使用 用户未必希望在单个页面上滚动查看成千上万条记录请确保您的应用程序设计合理能够处理可能会返回大量记录的情况有关如何在 Datagrid 中实现分页的信息请参阅 Paging in DataGrid QuickStart Tutorial在 Scott Mitchell 的文章 Creating a Pageable Sortable DataGrid 中可以找到更多的信息 忘记在每个 Datagrid 事件中执行 DataBind() 调用从而导致回发 一个常见的问题是当我点击 Datagrid 某一行中的 Edit(编辑)链接时页面回发且不包含任何数据这是什么错误?问题在于数据仅在页面第一次被调用时绑定到网格在每个 Datagrid 事件(editupdatecancelpage 或 sort)中请确保设置了 Datagrid 的 datasource 属性(除非已经在 <asp:Datagrid> 声明中通过声明的方式进行了设置)并对 Datagrid 调用了 databind() 方法 运行时不必要地在 Datagrid 中动态创建 Datagrid 控件或列 在某些业务和技术方案中在运行时创建 ASPNET 控件是必要的也是完全合适的例如有时需要在选择其他页面选项后才能在运行时确定用户界面或是要创建一个复合服务器控件其中的每个子控件都需要动态创建因为无法以声明的方式创建这些子控件如果遇到这些情况请注意提交页面时不要保留这些动态控件必须在页面生命周期的早期在每次回发时重新创建动态控件(例如在 page_init 事件中)警言创建控件要早创建控件要勤有关如何动态创建控件的详细信息请参阅 Microsoft Knowledge Base 文章 HOW TO:Dynamically Create Controls in ASPNET 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 就够了(请参阅示例代码) 表 Datagrid 事件与 ViewState 的依赖关系 |