简介

显示大量已经按类别(不是很多)排序的数据但没有类别分界线,用户很难找到所需要的类别。例如,数据库中只有9个类别(8个不同的类别和1个null),共81种产品.现在用一个GridView列出所有产品,假设有用户对类别Seafood的产品感兴趣,她一定会按类别排序,把Seafood产品排列在一起.排序后,用户便寻找Seafood产品开始和结束的地方。虽然是按英文字母排列类别不难找到Seafood,但仍要花些时间在GridView寻找。为了进一步的区分类别,许多网站使用类别分界线这种排序用户界面来区别不同的类别。例如像图1中的分界线可以使用户很快地找到需要的类别。


图1:不同组明显的区分开来
在这篇文章中我们将讲解如何创建这种排序用户界面.

步骤1:创建一个普通的,能够排序的GridView

在我们学习如何创建增强型排序用户界面之前,先创建一个普通的列出所有产品GridView并且能够排序.现在打PagingAndSorting文件夹下的CustomSortingUI.aspx,添加一个GridView,设置ID="ProductList",以一个ObjectDataSource为数据源,ObjectDataSource的数据从ProductsBLL类的GetProducts()取得。

接下来设置GridView的列,包括ProductName, CategoryName, SupplierName, UnitPrice绑定列和Discontinued复选框列,再设置GridView允许排序。设置完这些以后你应该可以在代码编辑看到下面这些代码:

<asp:GridView ID="ProductList" runat="server" AllowSorting="True" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="ProductName" HeaderText="Product" SortExpression="ProductName" />
        <asp:BoundField DataField="CategoryName" HeaderText="Category" ReadOnly="True" SortExpression="CategoryName" />
        <asp:BoundField DataField="SupplierName" HeaderText="Supplier" ReadOnly="True" SortExpression="SupplierName" />
        <asp:BoundField DataField="UnitPrice" DataFormatString="{0:C}" HeaderText="Price"
            HtmlEncode="False" SortExpression="UnitPrice" />
        <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued" SortExpression="Discontinued" />
    </Columns>
</asp:GridView>

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetProducts" TypeName="ProductsBLL"></asp:ObjectDataSource>
 

这时你在浏览器中预览你将看到类似图2的界面,数据按类别的字母顺序排序.


图2:可排序GridView按Category按序

步骤2:如何添加分界行

完成创建创建一个普通的,能够排序的GridView后,就要在每一个类别的第一行之前添加分界行。怎么把这些分界行添加进GridView呢?一开始我们会想到遍历GridView的所有行,遇到排序列中的值不同就插入分界行。按照这种想法我们自然倒想利用GridView的DataRowBound事件来实现,DataRowBound事件我们已经在基于数据的自定义格式化一章中讲过,DataRowBound事件通常应用于格式化数据行。但是,DataRowBound事件不能解决这个问题,因为不能用这个事件动态地添加行到GridView,GridView的Rows集合是只读的.

要添加行到GridView有以下3个方法:

  1. 添加分界行到GridView绑定的数据源中
  2. GridView绑定数据后,添加额外的TableRow对象到GridView的控件集
  3. 创建一个自定义服务器控件,扩展GridView控件,重写它的方法以重新构造GridView的结构

如果自定义排序用户界面广泛应用多个页面或多个网站,创建一个自定义服务器控件是最好的方法.但采用这种方法要写太多的代码并且要深入理解GridView控件的的内部原理。因此,我们在这篇文章中不考虑使用这种方法。另外两种不同的方法-添加分界行到GridView绑定的数据源中和在GridView绑定数据后操作它的子控件,值得讨论.

添加分界行到绑定GridView的数据源中

当GridView被绑定到数据源,GridView从数据源中的每一条记录创建一条GridViewRow.因此我们可以在数据绑定(binding)之前添加一条"分界记录",图3描述了这个过程.


图3:添加分界行到数据源原理图

"分界记录"这个术语之所以加引号是因为实际没有这条特殊的记录,我们只是在数据源中添加一些标记行。打个比方,绑定ProductsDataTable对象到GridView,ProductsDataTable由ProductRow组成。我们可以标记一条记录作为"分界记录"并且设置CategoryID为-1(因为-1不存在普通记录中).

使用这种方法要以下的步骤实现:
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表示当前行的值.

注意:我获得通过单元格(cell)的Text属性赋值给lastValue和currentValue,这只能应用的绑定列(BoundFields),对于其它种类的列如模板列(TemplateField),复选框列(CheckBoxField)等等是不可行的,我将会在后面说明如何解决非绑定列的取值问题.

比较lastValue和currentValue,如果不同就要添加分界行到GridView的控件层次结构中.取得当前行的索引,创建一个GridViewRow对象(它由TableCell组成)插入到GridView的控件层次结构中.另外我们要把分界行格式化成单独的一个单元格,宽度与GridView相同,样式与应用SortHeaderRowStyle样式(css文件在下面给出),显示的文字是排序列名(如Category)和组名(如SeaFood),最后把currentValue赋值给lastValue.下面给出css代码:

.SortHeaderRowStyle
{
    background-color: #c00;
    text-align: left;
    font-weight: bold;
    color: White;
}

完成上面的代码后,就可以对按绑定列排序后生成有分界行的排序界面(图5是按supplier排序后给出的截图).但是我现在还不能对其它种类的列(如模板列或者复选框列)生成用户定义排序界面,如图6所示(按Discontinue排序).

图5:绑定列排序

图6:按ChectBox列排序没有出现分界行

按复选框列排序没有出现分界行是的原因是代码通过获取TableCell的Text属性判断按哪一列排序的,但复选框列TableCell的Text是空的,我们要从TableCell包含的控件取得CheckBox控件.遇到这种类型的列,要判断CheckBox有没有打勾,把currentValue = gvr.Cells[sortColumnIndex].Text替换成以下代码:

string currentValue = string.Empty;
if (gvr.Cells[sortColumnIndex].Controls.Count > 0)
{
    if (gvr.Cells[sortColumnIndex].Controls[0] is CheckBox)
    {
        if (((CheckBox)gvr.Cells[sortColumnIndex].Controls[0]).Checked)
            currentValue = "Yes";
        else
            currentValue = "No";
    }

// ... Add other checks here if using columns with other
    //      Web controls in them (Calendars, DropDownLists, etc.) ...
}
else
    currentValue = gvr.Cells[sortColumnIndex].Text;

这段代码判断有没有控件存在排序列的TableCell中,如果有并且第一个控件是CheckBox,按照CheckBox的Checked属性给currentValue赋值为"Yes"或者"NO",要是绑定就把TableCell的Text属性值赋给currentValue.同样道理,模板列使用此方法.图7是完善代码按Discontinue排序后的截图.


图7:按CheckBox列排序出现分界行

注意:如果数据库中的CategoryID,SupplierID或UnitPrice 为NULL,那么在GridView将显示为空字符串,这意味着分界行是这样显示"Category:",你可以设置绑定列的 NullDisplayText属性更这种显示样式,或者在Render方法中利用currentValue设置分界行显示的文字.

总结

GridView没有内置自定义排序界面的功能,但我们通过一些代码改变GridView的控件层次结构就可以创建自定义排序界面,这篇文章讲解如何添加分界行到可排序的GridView中,让用户容易的区分不同的组的分界,更多自定义排序界面例子请访问Scott Guthrie的Blog中A Few ASP.NET 2.0 GridView Sorting Tips and Tricks一文.

转载于:https://www.cnblogs.com/Fskjb/archive/2010/02/24/1672461.html

asp.net创建自定义排序用户界面相关推荐

  1. 创建自定义排序用户界面

    简介 显示大量已经按类别(不是很多)排序的数据但没有类别分界线,用户很难找到所需要的类别.例如,数据库中只有9个类别(8个不同的类别和1个null),共81种产品.现在用一个GridView列出所有产 ...

  2. spreadsheet js中创建下拉列表_JS 中创建自定义排序方法

    原文:https://www.youtube.com/watch?v=zVevl-K-m7Y 译者:前端小智 为了保证的可读性,本文采用意译而非直译. 想优质文章请猛戳GitHub博客,一年百来篇优质 ...

  3. 自定义列_如何对Pandas DataFrame进行自定义排序

    Pandas DataFrame有一个内置方法sort_values(),可以根据给定的变量对值进行排序.该方法本身使用起来相当简单,但是它不适用于自定义排序,例如, t恤尺寸:XS.S.M.L和XL ...

  4. dataframe 排序_如何对Pandas DataFrame进行自定义排序

    作者|B. Chen 编译|VK 来源|Towards Data Science Pandas DataFrame有一个内置方法sort_values(),可以根据给定的变量对值进行排序.该方法本身使 ...

  5. 为 ASP.NET Datagrid 创建自定义列

    Marcie Robillard DatagridGirl.com 2003 年 9 月 简介 不得不承认,为 Microsoft® ASP.NET 编写 Datagrid 代码包括大量的重复工作.尽 ...

  6. [转]利用ASP.NET 2.0创建自定义Web控件(1)

    原址:http://hi.baidu.com/sjbh/blog/item/cc58fd1bd35d3ad2ad6e7593.html   简介 从使用基本的文本编辑器到创作标记页面,Web 开发已经 ...

  7. [ASP.NET MVC2 系列] ASP.NET MVC 之如何创建自定义路由约束

     [ASP.NET MVC2 系列]      [ASP.NET MVC2 系列] ASP.Net MVC教程之<在15分钟内用ASP.Net MVC创建一个电影数据库应用程序>      ...

  8. ASP.NET Core 配置 - 创建自定义配置提供程序

    ASP.NET Core 配置 - 创建自定义配置提供程序 在本文中,我们将创建一个自定义配置提供程序,从数据库读取我们的配置.我们已经了解了默认配置提供程序的工作方式,现在我们将实现我们自己的自定义 ...

  9. 在ASP.NET Core中创建自定义端点可视化图

    在上篇文章中,我为构建自定义端点可视化图奠定了基础,正如我在第一篇文章中展示的那样.该图显示了端点路由的不同部分:文字值,参数,动词约束和产生结果的端点: 在本文中,我将展示如何通过创建一个自定义的D ...

  10. [导入]Asp.net 2.0 自定义控件开发[创建自定义浮动菜单FloadMenu控件][示例代码下载]...

    Asp.net 2.0 自定义控件开发[创建自定义浮动菜单FloadMenu控件][示例代码下载] 文章来源:http://blog.csdn.net/chengking/archive/2007/0 ...

最新文章

  1. 如何使用Gradle的maven-publish将jar包或者war包上传到nexus仓库
  2. python 版本比较函数 LooseVersion StrictVersion
  3. CM: Relationship between Note created in Fiori UI and webclient UI
  4. Jerry的ABAP原创技术文章合集
  5. 一些有关使用EF的错误用法展开的思考
  6. 求解无约束最优化问题的共轭梯度法matlab程序,Matlab实现FR共轭梯度法
  7. 如何自己搭建一个网盘
  8. 深度:巨头覆盖之下中老年电商的创新突破策略-获客、选品、转化、粘性
  9. 未知USB设备(设备描述符请求失败)解决方法
  10. 月薪40K+银行测试经理,自动化测试实践经验分享
  11. 三星s9更新android9.0 体验,国行三星Galaxy S9系列更新Android 9.0 界面更漂亮
  12. 【微信小程序-原生开发】添加自定义图标(以使用阿里图标库为例)
  13. 联想y7000/r7000 2020款加装固态硬盘及硬盘分区,硬盘测速方法
  14. 哈工大计算机网络第一章——计算机网络概述复习
  15. 基于PCA 人脸识别/人脸识别算法/人脸检测程序源码MATLAB ELM+PCA人脸识别 PCA人脸识别matlab代码 基于PCA算法的人脸识别
  16. 图像处理问题解决师——求取每个颗粒到其他颗粒边缘的最近距离
  17. 计算机二级投影运算怎么看,二级计算机中交、并、除、自然连接、投影、选择和笛卡尔积是怎么计算的?...
  18. A Survey of Deep Learning-based Object Detection论文翻译 + 阅读笔记
  19. POI报错_org.apache.xmlbeans.impl.values.XmlValueDisconnectedException
  20. altera fpga大小如何衡量_【转】Xilinx和Altera的FPGA的对比

热门文章

  1. linux下mysql 8 忘记密码
  2. PostGis路径分析
  3. IO多路复用之select、poll、epoll介绍
  4. oracle+调整+表空间,oracle数据库表空间及权限调整示例
  5. 修改chrome中HTML元素,自由更改网页中的任何内容:Hack this page
  6. mysql锁表查询_如何通过自动增加索引,实现数据库查询耗时降低50%?
  7. C#:遍历JObject
  8. 1405 mysql 2800_mysql关于任何用户登录以及解决ERROR1405
  9. linux 的 swapper 进程不能sleep,深入理解perf报告中的swapper进程
  10. 论文笔记_S2D.40_2017_CVPR_半监督深度学习的单目深度图预测