一个非常漂亮且完整的自定义 GridView 分页器,没有 ViewState
如何实现一个自定义的 GridView 分页器,完全不依赖 ViewState 或 GridView 的分页功能。
引言
在我关于自定义 GridView 分页器的文章中,我收到了反馈,有人担心 Web 控件(DataSources、GridView
等)的分页能力依赖于 ViewState,从而影响了页面数据的加载大小。在这篇文章中,我为您呈现了原始 FullGridPager
类的 无 ViewState 版本。新类名为 FullGridPagerNVS
,其中 NVS 代表“NoViewState”(无 ViewState)。它实现了分页功能,而不依赖于 GridView
的分页功能——GridView
的 AllowPaging
属性设置为 false
。此外,没有使用数据源来绑定数据到 GridView
。这是通过两个数据层类(DataLayerHelper
和 CustomersDataLayer
)来实现的,它们只返回受行边界限制的相应行集。
图 1 展示了自定义分页器(格式与原始文章完全相同)。
背景
可选地,您可以参考我关于如何为 GridView
的 PagerTemplate
模板创建自定义分页器的 原始文章。
运行代码所需
除了 App_Code 文件夹中的 FullGridPagerNVS.cs 外,还需要以下文件才能使分页器正常工作:
- FullGridPagerNVS.css:分页器使用的样式。
- Images 文件夹:包含“第一页”、“上一页”、“下一页”和“最后一页”链接的图像。
- DataLayerHelper.cs:一个通用的数据库数据层类。
- CustomersDataLayer.cs:一个类,用于返回考虑分页的数据库行集。它使用了 Northwind 数据库的 Customers 表。
一如既往,ZIP 文件中包含了一个测试用的 ASPX 网页,用于演示 FullGridPagerNVS
类的用法。
- NVSTest.aspx 和 NVSTest.aspx.cs。
使用代码
由于这是一个非标准的 ASP.NET 实现,我将解释它是如何工作的。首先,我将列出此项目的主要关注点和限制:
- 不能使用数据源来获取数据。相反,代码编写了一个非常简单的数据层,用于在考虑分页的情况下从数据库获取数据。
DataLayerHelper
类是一个通用的数据层,它只对数据库执行参数化 SQL 查询。虽然它包含许多方法,但只有Get
和ExecuteScalar
对我们感兴趣。 GetCustomers
方法以DataTable
的形式返回 Customers 表的所有行。GetCustomersCount
方法返回 Customers 表中的总行数。GetPageCustomers
方法使用以上两个方法来返回一个行受限的DataTable
。它有两个参数:startIndex
:要开始检索的行号,以及maxPageRows
:每页显示的最大行数。
CustomersDataLayer
类使用 DataLayerHelper
方法查询 Northwind 数据库的 Customers 表,具体来说:
这样,我们就可以指定行边界,例如,如果 startIndex
= 10 且 maxPageRows
= 5,那么返回的行集将只包含行 10、11、12、13、14。请注意,startIndex
是从零开始的。下面的代码片段仅移除了所需边界之外的非必要行(行 0-9 和 15-max)。
public static DataTable GetPageCustomers(int startIndex, int maxPageRows)
{
// Delete the unneccessary rows and return the datatable.
DataTable tbl= GetCustomers();
int maxRows = GetCustomersCount();
int max = startIndex + (maxPageRows - 1);
if (max > maxRows) max = maxRows;
for (int i = 0; i < startIndex; i++)
tbl.Rows[i].Delete();
for (int i = max + 1; i < maxRows; i++)
tbl.Rows[i].Delete(); return tbl;
}
由于没有数据源,以下代码(NVSTest.aspx.cs 文件)用于手动将数据绑定到 GridView
。
GridView1.DataSource =
CustomersDataLayer.GetPageCustomers(StartIndex, PageSize); GridView1.DataBind();
GridView
必须将其 AllowPaging
属性设置为 false
,当然。因此,没有 PageIndex
或 PageCount
属性可供依赖。总行数也是我们必须知道的一个值。因此,这些值在网页代码中初始化,并存储在 Session 状态中。public partial class NVSTest : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e
{
if (!IsPostBack)
{
StartIndex = 0;
MaxRows = CustomersDataLayer.GetCustomersCount();
BindData();
}
else
ShowFullGridPagerNVS();
}
public int StartIndex
{
get { return (int)Session["startIndex"]; }
set { Session["startIndex"] = value; }
}
public int MaxRows
{
get { return (int)Session["maxRows"]; }
set { Session["maxRows"] = value; }
}
}
您也可以将它们存储在任何您喜欢的地方——甚至在 ViewState 中!以下是它们的含义:
StartIndex
:绑定的行集必须从此行开始。MaxRows
:绑定行集中的总行数。
考虑到以上几点,我对 FullGridPagerNVS
类做了一些修改。
- 除了
MaxVisiblePageNumbers
之外,总行数(MaxRows
)和每页行数(MaxPageRows
)必须作为参数传递。 - 该类计算总页数(
totalPages
)。这取代了GridView
的PageCount
属性。 - 该类通过将行索引(
StartIndex
)转换为页索引来计算当前页。
currentPageIndex = (int)Math.Ceiling((decimal)StartIndex / maxPageRows);
这取代了 GridView
的 PageIndex
属性。
PageTemplate
模板内。这会影响回发期间动态创建的控件的行为。该类现在动态创建所有必要的控件,包括“第一页”、“上一页”、“下一页”、“最后一页”链接以及页组 DropDownList
。请注意,在重新创建它们之前,HTML 容器会被清空。public void CreateCustomPager(Control Container, int StartIndex) {
[...]
HtmlTable pagerInnerTable =
(HtmlTable)Container.FindControl("pagerInnerTable");
if (pagerInnerTable != null)
{
// Remove the dynamically created cells before
// recreating them.
pagerInnerTable.Rows[0].Cells.Clear();
[...]
}
[...]
HtmlTable pagerOuterTable =
(HtmlTable)Container.FindControl("pagerOuterTable");
if (pagerOuterTable != null)
{
// Remove the pageGroups cell if it exists.
if (pagerOuterTable.Rows[0].Cells.Count > 1)
pagerOuterTable.Rows[0].Cells.RemoveAt(1);
[...]
}
}
CommandArgument
值不再是 PageIndex
值。页组 DropDownList
也是如此。FullGridPagerNVS
通过将每个页索引乘以每页的总行数来将每个页索引映射到起始行索引。例如:- 上一页按钮的值
((currentPageIndex - 1) * maxPageRows).ToString();
((i - 1) * maxPageRows).ToString();
((totalPages-1) * maxPageRows).ToString();
ddlPageGroups
选定的值new ListItem(group, (groupFirstPageNumber * maxPageRows).ToString());
StartIndex
值必须更改,并且 GridView
必须重新绑定数据。现在由网页(NVSTest.aspx)负责此责任。FullGridPagerNVS
类不了解数据绑定(而且这也不是它的业务)。但是,它必须提供处理动态创建的控件事件的手段。它通过指定两个事件处理程序来实现:public event CommandEventHandler PageNumberClick;
public event EventHandler PageGroupChange;
动态控件绑定到这些事件处理程序,例如:
lnkPage.Command += new CommandEventHandler(PageNumberClick);
最后,网页代码后置中所需的代码:
ullGridPager.PageNumberClick += new CommandEventHandler(lnkPage_Command);
fullGridPager.PageGroupChange += new EventHandler(ddlPageGroups_SelectedIndexChanged);
当用户点击页码链接时,会发生以下情况:
void lnkPage_Command(object sender, CommandEventArgs e)
{
StartIndex = Int32.Parse(e.CommandArgument.ToString());
BindData();
}
关注点
请确保您理解这是一个非标准的 ASP.NET 分页实现。这是基于我在关于如何创建自定义 GridView 分页器的文章中收到的反馈而进行的按需工作。我强烈建议您阅读原始文章,其中为您提供了直接、面向 ASP.NET 的解决方案。
历史
- 2007 年 10 月 6 日 - 实现 原始 FullGridPager 项目。
- 2007 年 10 月 14 日 - 实现 FullGridPagerNVS 项目。