使用这种方法要以下的步骤实现:
1.得到绑定到GirdView的数据(一个ProductsDataTable对象)
2.基于GridView的SortExpression和SortDirection属性排列数据
3.遍历ProductsDataTable中的ProductsRows,寻找排序列的分界。
4.在每组的分界处插入"分界行"ProductsRow到DataTable中,CategoryID列值为-1(或其它可以标记"分界行"的值).
5.插入"分界行"后动态地绑定数据到GridView.
完成以上5个步骤,还要在RowDataBound事件中判断哪些行是"分界行"(CategoryID=-1的行),格式化"分界行"的显示样式.此外还要再做一些工作,在Sorting事件中保留SortExpressiont和SortDirection的值.
GridView绑定数据后,添加额外的TableRow对象到GridView的控件集
相比在GridView绑定数据之前,在GridView绑定数据之后添加"分界行"更胜一筹.GridView是由一个Table构成,一个Table由Rows集构成,一个Row由Cells集构成,这就是GridView的控件层次.GridView根部是Table对象,再由数据源的每条记录生成GridViewRow (由TableRow派生出来),数据源的每一格的值又在GridViewRow生成TableCell.
我们可以利用GridView的控件层次构成以后在每组之间的添加分界行.因为GridView的控件层次结构是在页面呈现的时候创建的,所以重写Page类的Render方法,在需要的地方加上分界行,图4描述了这个过程.
图4:更改GridView控件层次结构添加界行原理图
这篇文章将用最后一个方法创建自定义排序用户界面.
注意:这里使用的代码是基于Teemu Keiski Blog中的Playing a Bit with GridView Sort Grouping一文.
步骤3:添加分界行到GridView的控件层次结构中
我们要在GridView的控件层次已经构造完毕后,以及在页面呈现之前添加分界行,必须在页面生命周期的最后阶段但又必须在GridView生成HTML语言之前进行,因此要重写Page类的Render方法,比如在下面的代码:
protected override void Render(HtmlTextWriter writer) { // Add code to manipulate the GridView control hierarchy base.Render(writer); }
当页面的原来的Render方法(base.Render(writer))被调用,页面的每个控件将被显示出来,产生出来的HTML标记基于控件层次.因此我们势必要在base.Render(writer)被调用之前更改GridView的控件层次结构.要添加分界行必须确保用户已经排好序,但刚开始GridView是没有按类别排好序的,不必要添加分界行.
注意:如果要使GridView默认是按某一列排序的,就要在Page_Load中调用GridView的Sort方法,注意要在if(!IsPostBack)中.请参考分页和排序数据(Paging and Sorting Report Data)一章获得关Sort方法的更多相关知识.
假设已经完成排序,下面要做的是判断是按哪一列排序并寻找该列不同组的分界处,下面的代码判断是否排序,按哪一列排序:
protected override void Render(HtmlTextWriter writer) { // Only add the sorting UI if the GridView is sorted if (!string.IsNullOrEmpty(ProductList.SortExpression)) { // Determine the index and HeaderText of the column that //the data is sorted by int sortColumnIndex = -1; string sortColumnHeaderText = string.Empty; for (int i = 0; i < ProductList.Columns.Count; i++) { if (ProductList.Columns[i].SortExpression.CompareTo(ProductList.SortExpression) == 0) { sortColumnIndex = i; sortColumnHeaderText = ProductList.Columns[i].HeaderText; break; } } // TODO: Scan the rows for differences in the sorted column's values }
假如GridView没有排序,SortExpression就没有设置值.我们要做的是对已经排序的GridView添加分界行.完成排序后,下一步要判断是按第几列排序,遍历每一列,比较SortExpression和哪一列的HeaderText相同,用两个变量sortColumnIndext和sortColumnHeaderText分别保存该列的索引和标题.
知道是按第几列排序后,最后一步是添加分界行到GridView中,遍历排序列的每一行,比较每上一行的值和它的当前行的值相不相同,不相同就要在中间插入分界行,代码如下:
protected override void Render(HtmlTextWriter writer) { // Only add the sorting UI if the GridView is sorted if (!string.IsNullOrEmpty(ProductList.SortExpression)) { // ... Code for finding the sorted column index removed for brevity ... // Reference the Table the GridView has been rendered into Table gridTable = (Table)ProductList.Controls[0]; // Enumerate each TableRow, adding a sorting UI header if // the sorted value has changed string lastValue = string.Empty; foreach (GridViewRow gvr in ProductList.Rows) { string currentValue = gvr.Cells[sortColumnIndex].Text; if (lastValue.CompareTo(currentValue) != 0) { // there's been a change in value in the sorted column int rowIndex = gridTable.Rows.GetRowIndex(gvr); // Add a new sort header row GridViewRow sortRow = new GridViewRow(rowIndex, rowIndex, DataControlRowType.DataRow, DataControlRowState.Normal); TableCell sortCell = new TableCell(); sortCell.ColumnSpan = ProductList.Columns.Count; sortCell.Text = string.Format("{0}: {1}", sortColumnHeaderText, currentValue); sortCell.CssClass = "SortHeaderRowStyle"; // Add sortCell to sortRow, and sortRow to gridTable sortRow.Cells.Add(sortCell); gridTable.Controls.AddAt(rowIndex, sortRow); // Update lastValue lastValue = currentValue; } } } base.Render(writer); }
首先获得GridView控件层次结构的根控件,一个Table,用gridTable表示.另外用字符串变量lastValue表示上一行的值,currentValue表示当前行的值.