65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET 增强型 GridView 自定义分页

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (10投票s)

2009年5月17日

CPOL

5分钟阅读

viewsIcon

66030

downloadIcon

1379

该 Grid View 是一个经过增强的、带有自定义分页的 Grid View。

引言

ASP.NET GridView 控件功能很强大,但缺少一些功能,例如数据库级别的分页。该控件可以进行分页,但它是 UI 级别的,很多情况下我们需要在数据库级别进行分页。因此,这里提供一个自定义控件,它还未完全完成,但到目前为止已经实现了基本的自定义分页功能。它最棒的地方在于没有使用任何第三方分页控件,而是利用了 GridView 本身内置的控件来完成所有工作!

分页的简单思路

要实现分页,总是需要三个要素:索引(Index)、页大小(PageSize)和总记录数(Total Records)。索引和页大小从 UI 获取,而总记录数则是在数据库级别完成分页过程后返回的。例如:我正在从数据库查询员工信息,数据库中存储了大约 455 条员工记录。我只查询数据库中的 10 条记录,并指定数据库获取哪 10 条记录。我不会解释数据库级别的分页机制,我只假设返回了 10 条记录,并且总记录数等于 455。

因此,当结果返回时,我应该向 `EGridView` 提供:总记录数 = 10,以及 `EmployeeCollection` 记录集。`GridView` 本身已经有了 `PageIndex` 和 `PageSize`。

ASP.NET GridView 已有哪些功能?

现在让我们看看 ASP.NET 原始 `GridView` 控件提供的属性。当然,其中一些属性与 GridView 中的数据源相关,但我们这里一般讨论 GridView 拥有的功能。

  • PageIndex:此属性保存索引,但不幸的是,它被控件内置的 UI 分页机制所使用,因此我们不会使用它,而是使用另一个属性。
  • PageSize:此属性保存我们期望的页大小,因此我们可以正常使用此属性,因为它大多数时候是固定的(除非您想在运行时更改它,这也没问题)。

现在,GridView 中还有其他一些属性,但它们是受保护的,无法在 `GridView` 控件外部看到。其中重要的属性是:

  • VirtualCount:此属性保存分页将要分页的总记录数,与我文章前面提到的 `TotalRecords` 相同。在 `GridView` 控件内部,它从绑定集合中的实体数量获取值(因为它是 UI 级别分页),您无法从外部设置或控制此值来进行分页。
  • CurrentPageIndex:此属性实际上是以 `PageIndex` 的形式暴露的,但我之所以提到它,是因为它是该值的实际控制器,因为它实际上是 `GridView` 控件内 `PagedDataSource` 实例的一个属性。

添加两个新属性

到目前为止,我们有了 `PageSize` 并且可以使用它,但是另外两个成员 `PageIndex` 和 `TotalRecords` 还没有,所以我们将把它们添加到我们的 `EGridView` 中。为了简单地保存它们的数据和持久性,我们将使用视图状态(View State)。以下是我们想要添加的两个属性的实现:

private Nullable<int> customPageIndex;
/// <summary>
/// Use CustomPageIndex instead of PageIndex for Pagination out of the grid
/// </summary>
public int CustomPageIndex
{
get
{ 
if (customPageIndex == null)
{
if (ViewState["CustomPageIndex"] == null)
CustomPageIndex = PageIndex;
else
{
CustomPageIndex = (int)ViewState["CustomPageIndex"];
}
}
return customPageIndex.Value;
}
set
{
customPageIndex = value;
ViewState["CustomPageIndex"] = value;
}
}
 
private Nullable<int> totalRecords;
/// <summary>
/// Gets or Sets the Total Records for pagination, 
/// its important to set the value of Total 
/// Records BEFORE binding the data to the grid. 
/// </summary>
public int TotalRecords
{
get
{
if (totalRecords == null)
{
if (ViewState["TotalRecords"] == null)
TotalRecords = PageIndex;
else
{
TotalRecords = (int)ViewState["TotalRecords"];
}
}
return totalRecords.Value;
}
set
{
totalRecords = value; 
ViewState["TotalRecords"] = value; 
}
}

重写 GridView 中的两个方法

现在,当我们了解了 GridView 为分页提供的公共和内部功能后,让我们开始编码。这里我将它做到尽可能简单,只需要重写两个方法来克服原始 UI 分页并替换为我们自己的:`InitializePager` 和 `OnPageIndexChanged`。请看下面的代码:

/// <summary>
/// Override it in order to set the value of VirtualCount and CurrentPageIndex
/// </summary>
/// <param name="row"></param>
/// <param name="columnSpan"></param>
/// <param name="pagedDataSource"></param>
protected override void InitializePager(GridViewRow row, int columnSpan, 
	PagedDataSource pagedDataSource)
{
if (pagedDataSource.IsPagingEnabled && (TotalRecords != pagedDataSource.VirtualCount))
{
pagedDataSource.AllowCustomPaging = true;
pagedDataSource.VirtualCount = TotalRecords;
pagedDataSource.CurrentPageIndex = CustomPageIndex; 
}

base.InitializePager(row, columnSpan, pagedDataSource); 
}
 
/// <summary>
/// Override it to avoid the popup message of not handling this event and 
/// to reset the selected index again.
/// </summary>
/// <param name="e"></param>
protected override void OnPageIndexChanging(GridViewPageEventArgs e)
{
//base.OnPageIndexChanging(e);
this.CustomPageIndex = e.NewPageIndex;
this.SelectedIndex = -1;
}

现在使用该控件很简单,我们都熟悉它。在 ASP.NET 中,您设置 `PageSize` 和 `AllowPaging=true`,并实现 `OnPageIndexChanged` 事件。在 ASP.NET 中这一切都没有什么新东西。在页面的代码隐藏文件中,您使用 `CustomPageIndex`、`PageSize` 和 `TotalRecords` 属性来实现分页。

关注点

现在,在分页机制中有一个有趣的要点需要我们注意。当我们从数据库将返回的 `Collection` 和 `TotalRecords` 绑定到 `EGridView` 控件时,您应该小心在绑定到 `EGridView` 之前设置 `TotalRecords` 属性。示例如下:

//Correct using of binding to get the pagination
grdView.TotalRecords = AllEmployeesCount; // AllEmployeesCount of Type Int
grdView.DataSource = employees;// employees is a collection (just an example)
grdView.DataBind();

现在,如果您错误地先进行了绑定,然后再设置 `TotalRecords` 属性,将不会发生任何分页,因为绑定使用了 `VirtualCount` 的值,而 `VirtualCount` 是通过我们的自定义属性 `TotalRecords` 设置的。

现在,要使用自定义控件,您有两种选择:要么将其放入程序集然后使用它,要么将其放入 Web 应用程序的 AppCode 文件夹中,然后从那里使用它。

我只解释第二种方法。如下所示:

  • 给它一个简单的命名空间,例如 `CustomControls`。
    namespace CustomControls
    {
    /// <summary>
    /// EGridView with tuned functionality to enable the manipulation 
    /// of Grid Pagination Control
    /// </summary>
    public class EGridView : GridView
    {...} 
  • 在您的 web.config 文件中添加以下行,以便在设计时页面中看到 `EGridView` 控件:
    <system.web>
    <pages>
    <controls>
    ...
    <add tagPrefix="CC" namespace="CustomControls"/> 
    ...
    </controls>

上面我们为命名空间 `CustomControls` 中的所有控件指定了一个标签前缀,以便在我们的 ASP.NET 页面中使用。

就是这样!

最后

我想说,这个控件仍在不断完善中。一个想法是,在页码之间注入一个小型文本框,用于指定要跳转的页码,而不是只能翻 10 页。我还有很多其他想法,但它们仍在开发中,不幸的是,我现在没有足够的时间去实现它们,但希望将来能够实现。

因此,欢迎任何 bug 报告或想法,以便在完善该控件时予以考虑。

历史

  • 2009 年 5 月 17 日:初始发布
© . All rights reserved.