数据绑定过程
DataBind 方法是所有 ASP.NET 控件公用的,对于数据绑定控件来说,它将触发用户界面的刷新以反映新数据。SqlPager 控件根据 SelectCommand 和 ConnectionString 属性的值,使用此方法启动数据检索操作。不言而喻,如果这些属性中的任何一个为空,该过程将终止。同样,如果合作者控件不存在,数据绑定过程将被取消。要查找合作者控件,DataBind 方法使用 Page 类中的 FindControl 函数。由此可见,合作者控件必须为主窗体的直接子控件。
进行分页显示的控件不能为任意的 ASP.NET 服务器控件。它必须为列表控件或基本数据列表控件。更一般来说,合作者控件必须具有 DataSource 属性并实现 DataBind 方法。可能进行分页的控件实际上只需要满足这些要求。Microsoft? .NET Framework 中所有继承 ListControl 或 BaseDataList 的控件都满足第一个要求;而所有 Web 控件通过设计都满足 DataBind 要求。使用当前的实现方法,无法使用 SqlPager 控件来对 Repeater 进行分页。Repeater 与合作者控件 DataList 和 DataGrid 不同,不继承 BaseDataList,也不提供列表控件的功能。下表列出了可以使用 SqlPager 进行分页的控件。
表 2:可以由 SqlPager 控件进行分页的数据绑定控件
控件 |
说明 |
CheckBoxList |
从 ListControl 派生而来,显示为复选框列表。 |
DropDownList |
从 ListControl 派生而来,显示为字符串下拉列表。 |
ListBox |
从 ListControl 派生而来,显示为字符串可滚动列表。 |
RadioButtonList |
从 ListControl 派生而来,显示为单选按钮列表。 |
DataList |
从 BaseDataList 派生而来,显示为模板化数据项目列表。 |
DataGrid |
从 BaseDataList 派生而来,显示为数据项目的表格网格。DataGrid 是唯一一个内置有功能强大的分页引擎的 ASP.NET 控件。 |
以下代码说明由 SqlPager 控件实现的数据绑定过程。
public override void DataBind() { // 启动数据绑定事件 base.DataBinding();
// 数据绑定后必须重新创建控件 ChildControlsCreated = false;
// 确保控件存在且为列表控件 _controlToPaginate = Page.FindControl(ControlToPaginate); if (_controlToPaginate == null) return; if (!(_controlToPaginate is BaseDataList || _controlToPaginate is ListControl)) return;
// 确保具有足够的连接信息并指定查询 if (ConnectionString == "" || SelectCommand == "") return;
// 获取数据 if (PagingMode == PagingMode.Cached) FetchAllData(); else FetchPageData();
// 将数据绑定到合作者控件 BaseDataList baseDataListControl = null; ListControl listControl = null; if (_controlToPaginate is BaseDataList) { baseDataListControl = (BaseDataList) _controlToPaginate; baseDataListControl.DataSource = _dataSource; baseDataListControl.DataBind(); return; } if (_controlToPaginate is ListControl) { listControl = (ListControl) _controlToPaginate; listControl.Items.Clear(); listControl.DataSource = _dataSource; listControl.DataBind(); return; } } |
根据 PagingMode 属性的值调用不同的获取例程。在任何情况下,结果集都绑定到 PagedDataSource 类的实例上。此类提供了一些用来对数据进行分页的功能。特别是,当整个数据集都存储在缓存中时,该类将自动检索当前页面的记录并返回布尔值,来提供有关第一页和最后一页的信息。稍后将回来介绍此类的内部结构。在上述列表中,帮助程序的 PagedDataSource 对象是由 _dataSource 变量表示的。
然后,SqlPager 控件经过计算得出合作者控件的类型,并将 PagedDataSource 对象的内容绑定到合作者控件的 DataSource 属性。
有时,上述的 DataBind 方法还将 ChildControlsCreated 属性重新设置为 false。那么,为什么要这样做呢?
当包含分页程序的页面返回时,所有控件都要重新创建;分页程序也不例外。通常情况下,所有控件及其子控件都是在准备显示页面之前创建的。在每个控件接收到 OnPreRender 通知之前的一瞬间,protected EnsureChildControls 方法将被调用,这样,每个控件都可以生成自己的控件树。此事件发生后,数据绑定过程完成,新数据已存储到缓存中。
但是,当由于单击分页程序的一个组成控件而使页面返回时(即用户单击以更改页面),就会生成分页程序的控件树,这时远未达到显示阶段。特别是,当处理相关的服务器端事件时,就必须生成控件树,因而是在数据绑定开始之前生成控件树。困难在于,数据绑定将修改页面索引,而这必须反映在用户界面中。如果不采取某些对策的话,当用户切换到另一页时,分页程序中的页面索引将不会被刷新。
有各种方法可以解决此问题,但重要的是要弄清楚问题及其真正的原因。您可以避免生成控件树,并在 Render 方法中生成所有输出。另外,您还可以修改树中受数据绑定更改影响的部分。本文选择了第三种方法,这种方法需要较少的代码,而且,不管控件的用户界面的哪个部分受到数据绑定更改的影响,都能够解决问题。通过将 ChildControlsCreated 属性设置为 false,可以使以前创建的任何控件树无效。这样,在显示之前将重新创建控件树。