转自:http://hi.baidu.com/sneer_owen/blog/item/ec85e0df164d4651cdbf1a02.html

导言:
       GridView 控件与 DataGrid 相比有了很大的改进,但仍不够完美,比如进行分组(group)和统计(summary).为了实现统计功能,我们可以在 RowDataBound 事件里进行编码;而分组则要复杂一些。如果同时实现这2种功能就更棘手了,基于这个难题我们可以考虑使用 GridViewHelper 类,就像其名称一样,它的用处在于构建分组和统计.

使用 GridViewHelper

下面我们将看一些 GridViewHelper 的示例.首先我们展示 groups 和 summaries 创建的方格.该示例的数据来自 Northwind 数据库,做了些许修改:


                                                                                              图1

要为 ItemTotal 列创建统计功能,我只需要2行代码:

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    helper.RegisterSummary("ItemTotal", SummaryOperation.Sum);
}

首先,我们创建 GridViewHelper,然后对指定的列注册 summary 功能,那么就可以执行 summary 操作了,结果如下图所示.


                                                                                             图2:

在该示例里,最下面新添加了一行以显示统计结果.不过,我们也可以在页脚行显示统计结果,而用不着新添加一行.不同的是,新添加一行时,只生成一个单元格来显示结果,而在页脚行显示时,所有的单元格都会显示出来.

现在我们来创建分组,代码如下:
protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    helper.RegisterGroup("ShipRegion", true, true);
    helper.ApplyGroupSort();
}

其中,RegisterGroup 方法的第一个参数定义了分组依据,也就是按哪个列来进行分组.当然也可以创建交叉分组(composite group),也就是按照几个列的组合进行分组.第二个参数指定了是否自动分组,就本例而言,为每个组的标头新创建一行.第三个参数指定是否把作为分组依据的那个列强制隐藏.而 ApplyGroupSort 方法将分组依据的那个列作为排序标准(sort expression),就本例而言,自然就是 ShipRegion 了.这么做是很有必要的,因为有可能数据从数据库检索来时已经进行了某种排序.如下图,ShipRegion 列已经被隐藏了:


                                                                                             图3

让我们来看一些更有趣的事情,向各个分组添加统计功能.如下:

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    helper.RegisterGroup("ShipRegion", true, true);
    helper.RegisterSummary("ItemTotal", SummaryOperation.Sum, "ShipRegion");
    helper.ApplyGroupSort();
}

这次,RegisterSummary 方法多了一个参数。该参数指定了创建统计功能的组的名称。组的名称自动由作为分组依据的那些列的名字生成.如果分组依据只有一个列,那么组的名称就是那一列的名称;如果分组依据有多个列,那么组名由这些列名按顺序串联起来,用加号("+")连接,如"ShipRegion+ShipName".下图为进行了分组且对每组添加统计功能的情况:


                                                                                     图4

我们还可以创建"等级组",如下所示:

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    helper.RegisterGroup("ShipRegion", true, true);
    helper.RegisterGroup("ShipName", true, true);
    helper.ApplyGroupSort();
}

结果如下:


                                                                              图5

GridViewHelper 有一些事件可以很容易的实现视觉或功能上的调整,如下:

图6:

GroupStart:当新的分组开始时发生,意思就是说,当在作为分组依据的列里发现新的值时.

GroupEnd:某个组的最后一行结束时发生.

GroupHeader:当自动的为某个组添加一个标头时发生.如果不是自动的分组的话将不会触发该事件.

GroupSummary:当为某个组生成统计功能时发生。如果不是自动分组的话将不会触发该事件,不过分组类型是 suppression group(我们将在后面介绍)的话,另当别论.

GeneralSummary:当算出最终累计数时发生.如果最终累计数是自动生成的,那么在添加统计行,且数字填充到行之后才触发该事件.

通过寥寥几行代码我们就可以改善界面,如下:

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    helper.RegisterGroup("ShipRegion", true, true);
    helper.RegisterGroup("ShipName", true, true);
    helper.GroupHeader += new GroupEvent(helper_GroupHeader);
    helper.ApplyGroupSort();
}
private void helper_GroupHeader(string groupName, object[] values, GridViewRow row)
{
    if ( groupName == "ShipRegion" )
    {
        row.BackColor = Color.LightGray;
        row.Cells[0].Text = "  " + row.Cells[0].Text;
    }
    else if (groupName == "ShipName")
    {
        row.BackColor = Color.FromArgb(236, 236, 236);
        row.Cells[0].Text = "     " + row.Cells[0].Text;
    }
}

改善后的界面如下:


                                                                                     图7:

更多分组选项

这里还有2个案例。第一个是交叉分组(composite group).第二个案例定义了一个 suppress group,其行为与 sql GROUP BY 字句一样,重复的值都过滤掉,且将summary操作建立在其它列的基础上.

下面我们将看到这些交叉组的代码以及界面:

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    string[] cols = new string[2];
    cols[0] = "ShipRegion";
    cols[1] = "ShipName";
    helper.RegisterGroup(cols, true, true);
    helper.ApplyGroupSort();
}


                                                                                             图8

我们可以向该分组添加统计功能.这次,我们将定义一个求平均数的操作,并添加一个显示该操作的label控件:

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    string[] cols = new string[2];
    cols[0] = "ShipRegion";
    cols[1] = "ShipName";
    helper.RegisterGroup(cols, true, true);
    helper.RegisterSummary("ItemTotal", SummaryOperation.Avg, "ShipRegion+ShipName");
    helper.GroupSummary += new GroupEvent(helper_GroupSummary);
    helper.ApplyGroupSort();
}

private void helper_GroupSummary(string groupName, object[] values, GridViewRow row)
{
    row.Cells[0].HorizontalAlign = HorizontalAlign.Right;
    row.Cells[0].Text = "Average";
}


                                                                                     图9:

最后这个示例将创建一个 suppress group.有一点很重要,如果定义了一个 suppress group 就不能创建其它的分组.同理,如果已经一个分组,也不能再定义一个 suppress group,如果你非要硬来的话将抛出一个异常.

下面我们将看到 suppress group 的代码以及界面:

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    helper.SetSuppressGroup("ShipName");
    helper.RegisterSummary("Quantity", SummaryOperation.Sum, "ShipName");
    helper.RegisterSummary("ItemTotal", SummaryOperation.Sum, "ShipName");
    helper.ApplyGroupSort();
}


                                                                                                     图10

那些没有在 summary 操作里定义的列,其包含的值没有显示出来.它提示某种信息:

"Column 'column_name' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause."

没有必要将那些无关的列显示出来。为此,我们调用一个方法将它们隐藏起来:

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    helper.SetSuppressGroup(rdBtnLstGroup.SelectedValue);
    helper.RegisterSummary("Quantity", SummaryOperation.Sum, "ShipName");
    helper.RegisterSummary("ItemTotal", SummaryOperation.Sum, "ShipName");
    helper.SetInvisibleColumnsWithoutGroupSummary();
    helper.ApplyGroupSort();
}

结果如下:

图11

Summary 操作

GridViewHelper 有3个内置的统计操作:sum, average 以及 row count.我们可以定制自己的统计操作.为此,我们要为 GridViewHelper 提供2个方法.第一个方法将会被方格(或组)里的每一行所调用,第二个方法将会被调用来返回结果.下面我们将展示一个用户自定义统计操作的示例.其返回最小值:

private List<int> mQuantities = new List<int>();

protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    helper.RegisterSummary("Quantity", SaveQuantity, GetMinQuantity);
}

private void SaveQuantity(string column, string group, object value)
{
    mQuantities.Add(Convert.ToInt32(value));
}

private object GetMinQuantity(string column, string group)
{
    int[] qArray = new int[mQuantities.Count];
    mQuantities.CopyTo(qArray);
    Array.Sort(qArray);
    return qArray[0];
}

在上面的代码中,2个方法都接受 group 和 column 名称.如果统计方法不涉及到 group,那么该参数为 null.这些方法都被每一行所调用,同时接受当前行的某列的值.最终效果如下:


                                                                                            图12
局限性

在上面的例子我们模拟(simulate)了一个"等级组"。虽然该方格看起来具有"层次感",但执行起来绝不会按层次进行.没有group 或 subgroup,只有 sequentially registered groups.不过,如果我们想对一个内镶组添加统计功能时,这倒是个问题.下面,我们将看在这种情况下将会发生什么情况:
protected void Page_Load(object sender, EventArgs e)
{
    GridViewHelper helper = new GridViewHelper(this.GridView1);
    helper.RegisterGroup("ShipRegion", true, true);
    helper.RegisterGroup("ShipName", true, true);
    helper.RegisterSummary("ItemTotal", SummaryOperation.Sum, "ShipName");
    helper.RegisterSummary("ItemTotal", SummaryOperation.Sum);
    helper.GroupSummary += new GroupEvent(helper_Bug);
    helper.ApplyGroupSort();
}

private void helper_Bug(string groupName, object[] values, GridViewRow row)
{
    if (groupName == null) return;

row.BackColor = Color.Bisque;
    row.Cells[0].HorizontalAlign = HorizontalAlign.Center;
    row.Cells[0].Text = "[ Summary for " + groupName + " " + values[0] + " ]";
}

图13

如上图所示,summary 在外部组(outer group)的标头创建后再创建.原因是,本来事件的发生顺序是:
Group1_Start
Group1_End
Group2_Start
Group2_End

对 hierarchical grouping 而言,事件发生顺序为:

Group1_Start
Group2_Start
Group2_End
Group1_End

贯彻

GridViewHelper 是作为一个独立类(standalone class)而不是继承类来贯彻的,这就使的利用GridViewHelper 来处理任何的 GridView 成为了可能。另外还有4个类:GridViewSummary, GridViewGroup, GridViewSummaryList 以及 GridViewGroupList.这些"list" classes 可以利用一个字符串索引来进行访问,如:
helper.GeneralSummaries["ItemTotal"].Value.

当创建 GridViewHelper 时,将对目标 GridView 的一个引用进行保存,且 RowDataBound 事件将绑定到一个方法完成实际的工作:

public GridViewHelper(GridView grd, bool useFooterForGeneralSummaries, SortDirection groupSortDirection)
{
    this.mGrid = grd;
    this.useFooter = useFooterForGeneralSummaries;
    this.groupSortDir = groupSortDirection;
    this.mGeneralSummaries = new GridViewSummaryList();
    this.mGroups = new GridViewGroupList();
    this.mGrid.RowDataBound += new GridViewRowEventHandler(RowDataBoundHandler);
}

GridViewHelper 内部使用的一些方法被定义为 public,因为如果必要的话可以将这些有用的方法进行用户定制.还有一些其它的操作选择没有在示例里进行演示,不过我们可以通过 Visual Studio 的智能感知系统来查证.

纪要:

对值类型的过多的的装箱和拆箱操作会对执行性能产生影响.为此,我们可以用泛型来贯彻这些内置的统计操作,但这并没有想象的那么容易,可以参阅文章《Using Generics for Calculations》或《Operator Overloading with Generics》。在现实生活中,这种影响不太显著,除非有数百万行,或有数千个用户分组,且同时进行数据统计操作.

在线案例将 GridView 的 EnableViewState 设置为 false. 这是必要的,因为当其为true,在一个页面回传时,GridView 控件将从 ViewState 进行重新绑定,而不会触发 RowDataBound 事件.我们可以在 ASP.Net 2.0里放心的禁用该 ViewState,因为 ControlState 仍然进行了保存.

转自:http://hi.baidu.com/sneer_owen/blog/item/ec85e0df164d4651cdbf1a02.html

示例代码http://www.agrinei.com/gridviewhelper/gridviewhelpersample_en.zip

转载于:https://www.cnblogs.com/DonaldTang/archive/2010/03/17/1687878.html

转贴:girdview分组,统计,排序的解决方案相关推荐

  1. MySQL连表分组统计使用count查询出数据不准确问题解决方案

    先上两副图 这里有两张表:score表和year_as表,要求统计出score表按年份分组的个数,且查询出来的内容需要包括year_as表中的year_as字段. 使用正常连表并分组统计count得出 ...

  2. SQL service基础(二)对数据指定列查询、条件查询、查询结果排序、聚集函数查询、分组统计查询

    实验目标: 1.掌握指定列或全部列查询 2.掌握按条件查询 3.掌握对查询结果排序 4.掌握使用聚集函数的查询 5.掌握分组统计查询 一.请完成书中实验7.1,并完成以下问题. 1.查询所有学生的姓名 ...

  3. Java 8 辣么大(lambda)表达式不慌之—–(五)示例-Collectors中的统计、分组、排序等

    Java 8 辣么大(lambda)表达式不慌之-–(五)示例-Collectors中的统计.分组.排序等 summarizingInt 按int类型统计 maxBy取最大/minBy取最小 aver ...

  4. MongoDb数组操作 - unwind解包、group分组统计、sort排序

    MongoDB统计文档(Document)的数组(Array)中的各个元素出现的次数 一,问题描述 [使用 unwind 操作符 "解包" Document 里面的Array中的每 ...

  5. es统计有多少个分组_ES 24 - 如何通过Elasticsearch进行聚合检索 (分组统计)

    1 普通聚合分析 1.1 直接聚合统计 (1) 计算每个tag下的文档数量, 请求语法: GET book_shop/it_book/_search { "size": 0, // ...

  6. 编写MapReduce程序,统计每个买家收藏商品数量,实现统计排序功能

    实验材料及说明 在Ubuntu系统的/学号(每个人用自己的学号)/salesInfo目录下,有买家的购买记录文件Sales,该文件记录了买家的id,购买商品的id以及购买日期,文件为名为Sales.S ...

  7. ROW_NUMBER() OVER()函数用法;(分组,排序),partition by

    1.row_number() over()排序功能: (1) row_number() over()分组排序功能: 在使用 row_number() over()函数时候,over()里头的分组以及排 ...

  8. 问题 B: 分组统计

    分组统计 问题 B: 分组统计时间限制: 1 Sec 内存限制: 32 MB 提交: 416 解决: 107 [提交][状态][讨论版][命题人:外部导入] 题目描述 先输入一组数,然后输入其分组,按 ...

  9. asc desc排序_HIVE的学习之路(六)Hive的分组Join排序

    分组 Group By语句 GROUP BY语句通常会和聚合函数一起使用,按照一个或者多个列队结果进行分组,然后对每个组执行聚合操作. 案例实操: (1)计算emp表每个部门的平均工资 hive (d ...

  10. mongodb按照时间分组统计

    使用spring data mongodb v1.8 需求1. 数据结构如下.说明:改集合记录的是公司各个系统的访问情况(localPath表示系统,requestTime 表示请求时间,字符串类型, ...

最新文章

  1. 【Smart_Point】unique_ptr中独占指针使用MakeFrame
  2. swoole 异步redis
  3. 一个孩子能长大成人到底有多不容易? | 今日最佳
  4. 潘在亮:给业务开发提供黑科技装备的“测试Q博士”
  5. 向Excle中插入多个表
  6. python 前端开发_python和前端开发怎么抉择?
  7. IntelliJ IDEA 下载安装以及破解码大集合
  8. GitLab 创建项目组及将代码导入项目
  9. android netd firewall 分析,第2章 深入理解Netd
  10. 【社招】量化研究员(机器学习)-Akuna Capital -上海
  11. 西门子博图功能指令(移动块)
  12. Android组件化开发实践和案例分享 1
  13. 利用R语言对泰坦尼克号沉没事件幸存者的数据分析与预测
  14. 腾讯云的服务器解析域名步骤
  15. 数学建模实战9(聚类分析)
  16. 智能文档控制——文档的智能归档、捕获、索引、访问和协作
  17. Python Web前端实战案例——电商网站商品菜单导航栏
  18. 人脸识别论文:Partial FC: Training 10 Million Identities on a Single Machine
  19. python 之Entry
  20. ORAN专题系列-16:5G O-RAN FrontHaul前传接口的网络配置管理协议netconf

热门文章

  1. 微信启动界面:张小龙的情怀和马化腾的爱好
  2. VB.net MessageBox弹出的确认对话框点击确定按钮
  3. 松翰SN8F5703单片机WDT例程
  4. sql server查询不显示结果_仅凭网上查询结果显示邮件由行政机关签收,能证明行政机关一定收到了当事人的申请吗?...
  5. 基于遗传算法优化的BP神经网络算法
  6. 移动常见业务单词和词组
  7. Unity VFX学习系列 —— Operators 详细说明
  8. linux rd类型文件,RD 文件扩展名: 它是什么以及如何打开它?
  9. 潭州学院html学习(day02)
  10. 怎么修改服务器文件写入权限,怎么修改服务器本地写入权限设置