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






4.20/5 (13投票s)
2007 年 3 月 17 日
2分钟阅读

105547

671
本文介绍如何实现与对象数组一起工作的GridView控件的分页和排序。
引言
这种数据呈现模型相当常见:一个对象数组绑定到具有预定义列的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
控件有一个排序事件处理程序,但它不保存关于先前排序状态的信息。因此,我添加了一些变量来保存数据:PreviousSortExpression
、CurrentSortExpression
和CurrentSortDirection
。
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();
}
ArrayComparer
是IComparer
接口的实现,用于按指定顺序(升序或降序)比较两个对象的指定属性。
如何使用
首先,因为我将所有分页和排序功能隐藏在新控件中,所以我必须明确拒绝旧的数据绑定方法。因此,我为所有数据源请求添加了一个事件处理程序以及调用数据绑定方法的方法。并且,还需要允许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>>
这就是使用此控件所需的一切,无需额外的工作即可进行分页或排序。完整的代码可以在上面的演示中找到。