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

为 GridView 控件实现分页和排序,该控件与对象数组配合使用

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.20/5 (13投票s)

2007 年 3 月 17 日

2分钟阅读

viewsIcon

105547

downloadIcon

671

本文介绍如何实现与对象数组一起工作的GridView控件的分页和排序。

Screenshot - gridviewex.gif

引言

这种数据呈现模型相当常见:一个对象数组绑定到具有预定义列的GridView控件。DotNetNuke web框架普及了这种模型,它具有使用业务对象而不是数据表的无名行的优势。一个经典的例子

<asp:GridView id="gv" runat="server" AutoGenerateColumns="False" ...
    <Columns>
        <asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name"  />
        ... 
    </Columns>
</asp:GridView>

以及在Page_Load中的其他地方

if (!IsPostBack)
{
    gv.DataSource = someArray;
    gv.DataBind();
}

在我看来,这是一个相当不错的模型。但是,如果GridView控件绑定到对象数组,则它没有内置的排序和分页功能。让我们来实现它。

代码概述

我从GridView控件继承我的控件,并重写OnInit方法以添加两个事件处理程序。

this.PageIndexChanging += new GridViewPageEventHandler(BaseGridView_PageIndexChanging);
this.Sorting += new GridViewSortEventHandler(BaseGridView_Sorting);

分页的实现很简单。

void BaseGridView_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
     this.PageIndex = e.NewPageIndex;
     BindDataSource();
}

排序则比较复杂。GridView控件有一个排序事件处理程序,但它不保存关于先前排序状态的信息。因此,我添加了一些变量来保存数据:PreviousSortExpressionCurrentSortExpressionCurrentSortDirection

void BaseGridView_Sorting(object sender, GridViewSortEventArgs e)
{
      //for unknown reason e.SortExpression always is Ascending
      if (PreviousSortExpression == e.SortExpression)
      {
          e.SortDirection = SortDirection.Descending;
          PreviousSortExpression = null;
      }
      else
          PreviousSortExpression = e.SortExpression;

     CurrentSortExpression = e.SortExpression;
     CurrentSortDirection = e.SortDirection;
     ChangeHeaders(this.HeaderRow);
     BindDataSource();
}

还缺少一点东西。没有直观的显示网格是否已排序以及如何排序。因此,我更改了已排序的列标题以显示此信息。我通过两个 Unicode 符号来实现:向上箭头(\u25bc)和向下箭头(\u25b2)。

private void ChangeHeaders(GridViewRow headerRow)
{
    for (int i = 0; i < headerRow.Cells.Count; i++)
    {
        if (headerRow.Cells[i] is DataControlFieldCell)
        {
            DataControlField field = 
              ((DataControlFieldCell)headerRow.Cells[i]).ContainingField;

            //remove all previous sorting marks if they exist
            Regex r = new Regex(@"\s(\u25bc|\u25b2)");
            field.HeaderText = r.Replace(field.HeaderText, "");

            if (field.SortExpression != null && field.SortExpression == 
                CurrentSortExpression)
            {
                //add current sorting state mark
                if (CurrentSortDirection == SortDirection.Ascending)
                    field.HeaderText += " \u25b2";
                else
                    field.HeaderText += " \u25bc";
            }
        }
    }
}

现在,关于用数据填充网格。我添加了在请求数据源时发生的事件以及将处理此事件的方法。

public delegate void DataSourceRequestedEventHandler(out Array dataSource);
public event DataSourceRequestedEventHandler DataSourceRequested;

当用户排序网格或更改当前页时,会重新填充网格。对于初始填充,使用BindDataSource方法。

public void BindDataSource()
{
    Array dataSource = null;
  
    //request for the data source
    if (DataSourceRequested != null)
       DataSourceRequested(out dataSource);
    
    if (dataSource == null)  
       throw new Exception("Failed to get data source.");   

    //sort the data in case of need
    if (CurrentSortExpression != null)
    {
        ArrayList ar = new ArrayList(dataSource);
        ar.Sort(new ArrayComparer(CurrentSortExpression, 
                                  CurrentSortDirection));
        dataSource = ar.ToArray();
    }
   
    base.DataSource = dataSource;
    base.DataBind();
}

ArrayComparerIComparer接口的实现,用于按指定顺序(升序或降序)比较两个对象的指定属性。

如何使用

首先,因为我将所有分页和排序功能隐藏在新控件中,所以我必须明确拒绝旧的数据绑定方法。因此,我为所有数据源请求添加了一个事件处理程序以及调用数据绑定方法的方法。并且,还需要允许GridView中的分页和排序 :)

<cc:GridViewEx ID="gv" runat="server" AllowPaging=True AllowSorting=True 
        OnDataSourceRequested="gv_DataSourceRequested" 
        AutoGenerateColumns="False">
    <Columns>
        <asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name"  />
        ... 
    </Columns>>

这就是使用此控件所需的一切,无需额外的工作即可进行分页或排序。完整的代码可以在上面的演示中找到。

© . All rights reserved.