GridView使用【GridViewHelper】分组统计
内容摘自:http://www.agrinei.com/gridviewhelper/gridviewhelper_en.htm
GridView在DataGrid上有很多改进,但仍然缺少一些非常重要的特性。GridView中不可使用的重复需求是创建组和汇总。要创建总结,我们可以轻松地编写RowDataBound事件。分组是一个更复杂的任务,需要更多的编码和调试。但当我们需要结合这两个特性时,事情就会变得一团糟。考虑到这一点,我已经实现了GridViewHelper,顾名思义,它是帮助创建组和总结的助手类。
使用GridViewHelper
下面我们将看到一些GridViewHelper示例。首先,我们展示将创建组和汇总的网格。样本数据来自Northwind数据库,有一些修改:
ShipRegion | ShipName | OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|---|---|
NM | Old World Delicatessen | 10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
NM | Old World Delicatessen | 10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
NM | Old World Delicatessen | 10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
NM | Old World Delicatessen | 10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
OR | Save-a-lot Markets | 10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
OR | Save-a-lot Markets | 10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
OR | Save-a-lot Markets | 10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
OR | Gourmet Lanchonetes | 10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
OR | Split Rail Beer & Ale | 10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
OR | Split Rail Beer & Ale | 10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
OR | Lazy K Kountry Store | 10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
NM | Old World Delicatessen | 10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
NM | White Clover Markets | 10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
NM | White Clover Markets | 10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
NM | White Clover Markets | 10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
ShipRegion | ShipName | OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|---|---|
NM | Old World Delicatessen | 10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
NM | Old World Delicatessen | 10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
NM | Old World Delicatessen | 10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
NM | Old World Delicatessen | 10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
OR | Save-a-lot Markets | 10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
OR | Save-a-lot Markets | 10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
OR | Save-a-lot Markets | 10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
OR | Gourmet Lanchonetes | 10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
OR | Split Rail Beer & Ale | 10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
OR | Split Rail Beer & Ale | 10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
OR | Lazy K Kountry Store | 10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
NM | Old World Delicatessen | 10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
NM | White Clover Markets | 10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
NM | White Clover Markets | 10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
NM | White Clover Markets | 10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
要为ItemTotal列创建一个摘要,我们只需要承诺的2行代码:
{
GridViewHelper helper = new GridViewHelper(this.GridView1);
helper.RegisterSummary("ItemTotal", SummaryOperation.Sum);
}
首先,我们创建GridViewHelper设置网格,在该网格中它将在构造函数中执行。然后,我们注册摘要,说明要执行的列名和摘要操作。下面的结果是:
ShipRegion | ShipName | OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|---|---|
NM | Old World Delicatessen | 10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
NM | Old World Delicatessen | 10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
NM | Old World Delicatessen | 10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
NM | Old World Delicatessen | 10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
OR | Save-a-lot Markets | 10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
OR | Save-a-lot Markets | 10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
OR | Save-a-lot Markets | 10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
OR | Gourmet Lanchonetes | 10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
OR | Split Rail Beer & Ale | 10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
OR | Split Rail Beer & Ale | 10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
OR | Lazy K Kountry Store | 10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
NM | Old World Delicatessen | 10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
NM | White Clover Markets | 10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
NM | White Clover Markets | 10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
NM | White Clover Markets | 10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
US$ 20.550,10 |
在这个示例中,添加了一条新行来显示摘要。另一种方法是使用footer row来显示摘要,而不是创建一个新的。当在网格中添加一个新行时,只创建需要显示汇总列的所需单元格。使用footer,创建所有的单元格。在组摘要的情况下,所有单元的生成或仅需要的单元格是一个组属性。
现在我们将创建一个组。代码如下:
{
GridViewHelper helper = new GridViewHelper(this.GridView1);
helper.RegisterGroup("ShipRegion", true, true);
helper.ApplyGroupSort();
}
RegisterGroup方法的第一个参数定义了要创建的组的列。还可以创建一个复合组,包括列的数组。第二个参数指定该组是否为automatic。在这种情况下,将自动为组头创建一个新的行。第三个参数指定是否必须隐藏组列。ApplyGroupSort方法将网格的排序表达式设置为分组列,在本例中是ShipRegion。这需要对工作进行适当的分组,除非数据来自数据库。
在上面的样本中,ShipRegion的专栏已经被隐藏了:
ShipName | OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|---|
NM | |||||
Old World Delicatessen | 10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
Old World Delicatessen | 10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
Old World Delicatessen | 10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
Old World Delicatessen | 10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
Old World Delicatessen | 10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
White Clover Markets | 10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
White Clover Markets | 10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
White Clover Markets | 10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
OR | |||||
Save-a-lot Markets | 10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
Save-a-lot Markets | 10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
Save-a-lot Markets | 10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
Gourmet Lanchonetes | 10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
Split Rail Beer & Ale | 10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
Split Rail Beer & Ale | 10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
Lazy K Kountry Store | 10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
Let's make something more interesting, let's add a summary to the created group. We need just one more line to register the summary to the group:
{
GridViewHelper helper = new GridViewHelper(this.GridView1);
helper.RegisterGroup("ShipRegion", true, true);
helper.RegisterSummary("ItemTotal", SummaryOperation.Sum, "ShipRegion");
helper.ApplyGroupSort();
}
This time, the RegisterSummary method takes another parameter. The parameter specifies the name of the group to which the summary must be created. Group name is automatically generated from the group column names. If the group has only one column, group name will be the name of that column. If the group has more than one column, the group name will be the ordered concatenation of the columns that composes the group, joined with a plus sign ("+"): "ShipRegion+ShipName".
We can see below the grid with grouping and a summary for the group:
ShipName | OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|---|
NM | |||||
Old World Delicatessen | 10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
Old World Delicatessen | 10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
Old World Delicatessen | 10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
Old World Delicatessen | 10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
Old World Delicatessen | 10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
White Clover Markets | 10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
White Clover Markets | 10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
White Clover Markets | 10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
US$ 18.465,10 | |||||
OR | |||||
Save-a-lot Markets | 10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
Save-a-lot Markets | 10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
Save-a-lot Markets | 10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
Gourmet Lanchonetes | 10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
Split Rail Beer & Ale | 10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
Split Rail Beer & Ale | 10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
Lazy K Kountry Store | 10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
US$ 2.085,00 |
It's possible to create more than one group in the grid, simulating a hierarchical grouping, as seen below:
{
GridViewHelper helper = new GridViewHelper(this.GridView1);
helper.RegisterGroup("ShipRegion", true, true);
helper.RegisterGroup("ShipName", true, true);
helper.ApplyGroupSort();
}
Result:
OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|
NM | ||||
Old World Delicatessen | ||||
10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
White Clover Markets | ||||
10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
OR | ||||
Lazy K Kountry Store | ||||
10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
Gourmet Lanchonetes | ||||
10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
Split Rail Beer & Ale | ||||
10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
Save-a-lot Markets | ||||
10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
Visualization is compromised when there is more than one group. GridViewHelper has events to allow easy implementation of visual or functional adjusts. The list of events follows below:
GroupStart | Occurs when a new group starts, it means, when new values are found in the group column. |
GroupEnd | Occurs in the last row of the group |
GroupHeader | Occurs when an automatic header row is added for the group. The event is not triggered if the group is not automatic. |
GroupSummary | Occurs when the summary row is generated for the group. The event is not triggered if the group is not automatic, but will be triggered if the group is a suppression group (will be seen later on). |
GeneralSummary | Occurs after the general summaries be calculated. If the summary is automatic the event occurs after the summary row be added and after the summary values be placed in the row. |
FooterDataBound | Occurs in the footer databinding. |
With a few more lines of code we can improve the visual aspect of the grid:
{
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;
}
}
The grid after the cosmetics:
OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|
NM | ||||
Old World Delicatessen | ||||
10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
White Clover Markets | ||||
10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
OR | ||||
Lazy K Kountry Store | ||||
10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
Gourmet Lanchonetes | ||||
10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
Split Rail Beer & Ale | ||||
10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
Save-a-lot Markets | ||||
10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
More grouping options
There are two more interesting samples. The first presents a composite group. The second defines a suppress group, that has the same behavior of the sql GROUP BY clause. The repeating values are suppressed, and a summary operation is performed on the other columns.
Below we can see the code and the grid appearance for the composite group:
{
GridViewHelper helper = new GridViewHelper(this.GridView1);
string[] cols = new string[2];
cols[0] = "ShipRegion";
cols[1] = "ShipName";
helper.RegisterGroup(cols, true, true);
helper.ApplyGroupSort();
}
OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|
NM - Old World Delicatessen | ||||
10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
NM - White Clover Markets | ||||
10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
OR - Lazy K Kountry Store | ||||
10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
OR - Gourmet Lanchonetes | ||||
10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
OR - Split Rail Beer & Ale | ||||
10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
OR - Save-a-lot Markets | ||||
10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
We can add a summary to the group. This time we will define an average operation and add a label to indicate the operation:
{
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";
}
OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|
NM - Old World Delicatessen | ||||
10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
Average | US$ 3.422,30 | |||
NM - White Clover Markets | ||||
10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
Average | US$ 451,20 | |||
OR - Lazy K Kountry Store | ||||
10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
Average | US$ 108,00 | |||
OR - Gourmet Lanchonetes | ||||
10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
Average | US$ 155,00 | |||
OR - Split Rail Beer & Ale | ||||
10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
Average | US$ 561,00 | |||
OR - Save-a-lot Markets | ||||
10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
Average | US$ 233,33 |
The last sample will create a suppress group. It's important to mention that if a suppress group is defined, no other group may be created. In the same way, if there is already a group defined, we can't create a suppress group and an exception will be raised if we try it.
Below we can see the code and the grid appearance for the suppress group:
{
GridViewHelper helper = new GridViewHelper(this.GridView1);
helper.SetSuppressGroup("ShipName");
helper.RegisterSummary("Quantity", SummaryOperation.Sum, "ShipName");
helper.RegisterSummary("ItemTotal", SummaryOperation.Sum, "ShipName");
helper.ApplyGroupSort();
}
ShipRegion | ShipName | OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|---|---|
Lazy K Kountry Store | 9 | US$ 108,00 | ||||
Gourmet Lanchonetes | 20 | US$ 155,00 | ||||
Old World Delicatessen | 147 | US$ 17.111,50 | ||||
White Clover Markets | 59 | US$ 1.353,60 | ||||
Split Rail Beer & Ale | 66 | US$ 1.122,00 | ||||
Save-a-lot Markets | 33 | US$ 700,00 |
No value is displayed for the columns that don't have a summary operation defined. This makes sense because GridViewHelper doesn't know how to proceed to summarize the values found in the group rows to a unique value. This reminds the certain known message:
"Column 'column_name' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause."
It doesn't make sense to display the columns that don't have a summary operation, and to hide them we need to call a method:
{
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();
}
I know, it's a big big name! The resulting grid can be seen below:
ShipName | Quantity | ItemTotal |
---|---|---|
Lazy K Kountry Store | 9 | US$ 108,00 |
Gourmet Lanchonetes | 20 | US$ 155,00 |
Old World Delicatessen | 147 | US$ 17.111,50 |
White Clover Markets | 59 | US$ 1.353,60 |
Split Rail Beer & Ale | 66 | US$ 1.122,00 |
Save-a-lot Markets | 33 | US$ 700,00 |
Summary operations
GridViewHelper has 3 built-in summary operations: sum, average and row count. A very useful feature is the possibility of define custom summary operations. To achieve this we need to provide two methods to the GridViewHelper. A method will be called for each row found in the grid (or group) and the other will be called to retrieve the result of the summary operation. Below we have a sample of a custom summary operation. The semi-dummy operation will return the minimum value found:
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];
}
In the code above we can see the required methods signatures. Both receive the summarized group and column names. If the summary is not relative to a group, the group parameter will be null. The method that is called for each row found in the grid, receives also the value of the column in the current row.
The resulting grid can be seen below :
ShipRegion | ShipName | OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|---|---|
NM | Old World Delicatessen | 10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
NM | Old World Delicatessen | 10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
NM | Old World Delicatessen | 10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
NM | Old World Delicatessen | 10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
OR | Save-a-lot Markets | 10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
OR | Save-a-lot Markets | 10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
OR | Save-a-lot Markets | 10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
OR | Gourmet Lanchonetes | 10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
OR | Split Rail Beer & Ale | 10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
OR | Split Rail Beer & Ale | 10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
OR | Lazy K Kountry Store | 10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
NM | Old World Delicatessen | 10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
NM | White Clover Markets | 10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
NM | White Clover Markets | 10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
NM | White Clover Markets | 10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
4 |
Limitations
In one sample we said that we can simulate a hierarchical grouping. Although the grid appears to present a hierarchical grouping, the actual implementation isn't hierarchical. There's no group or subgroup. There are only sequentially registered groups. This becomes a problem if we need to create a summary for an inner group. Below we can see what happens in this situation:
{
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] + " ]";
}
OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|
NM | ||||
Old World Delicatessen | ||||
10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
[ Summary for ShipName Old World Delicatessen ] | US$ 17.111,50 | |||
White Clover Markets | ||||
10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
OR | ||||
[ Summary for ShipName White Clover Markets ] | US$ 1.353,60 | |||
Lazy K Kountry Store | ||||
10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
[ Summary for ShipName Lazy K Kountry Store ] | US$ 108,00 | |||
Gourmet Lanchonetes | ||||
10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
[ Summary for ShipName Gourmet Lanchonetes ] | US$ 155,00 | |||
Split Rail Beer & Ale | ||||
10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
[ Summary for ShipName Split Rail Beer & Ale ] | US$ 1.122,00 | |||
Save-a-lot Markets | ||||
10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
[ Summary for ShipName Save-a-lot Markets ] | US$ 700,00 | |||
US$ 20.550,10 |
As we can see, the summary is created after the header of the outer group. This occurs because the event sequence is:
Group1_Start
Group1_End
Group2_Start
Group2_End
To a hierarchical grouping, the event sequence should be:
Group1_Start
Group2_Start
Group2_End
Group1_End
Implementation
GridViewHelper was implemented as a standalone class instead of an inherited class. This makes possible to use the GridViewHelper with any GridView, and doesn't force the developer to inherit a specific GridView, what could affect the classes design. There's another four classes in the solution: GridViewSummary, GridViewGroup, GridViewSummaryList and GridViewGroupList. The "list" classes were created to allow access by a string indexer: helper.GeneralSummaries["ItemTotal"].Value.
When the GridViewHelper is created, a reference to the target GridView is saved, and the RowDataBound event is bound to the method that does the hard work:
{
this.mGrid = grd;
this.useFooter = useFooterForGeneralSummaries;
this.groupSortDir = groupSortDirection;
this.mGeneralSummaries = new GridViewSummaryList();
this.mGroups = new GridViewGroupList();
this.mGrid.RowDataBound += new GridViewRowEventHandler(RowDataBoundHandler);
}
Some methods used internally by the GridViewHelper were defined public because they provide some useful features that may be needed for some customizations. There are a few other options that wasn't shown in the samples but that can be easily verified with Visual Studio intellisense.
要为ItemTotal列创建一个摘要,我们只需要承诺的2行代码
{
GridViewHelper helper = new GridViewHelper(this.GridView1);
helper.RegisterSummary("ItemTotal", SummaryOperation.Sum);
}
First we create the GridViewHelper setting the grid in which it will act in the constructor. Then we register the summary specifying the column name and the summary operation to be performed. The result is below:
ShipRegion | ShipName | OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|---|---|
NM | Old World Delicatessen | 10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
NM | Old World Delicatessen | 10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
NM | Old World Delicatessen | 10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
NM | Old World Delicatessen | 10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
OR | Save-a-lot Markets | 10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
OR | Save-a-lot Markets | 10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
OR | Save-a-lot Markets | 10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
OR | Gourmet Lanchonetes | 10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
OR | Split Rail Beer & Ale | 10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
OR | Split Rail Beer & Ale | 10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
OR | Lazy K Kountry Store | 10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
NM | Old World Delicatessen | 10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
NM | White Clover Markets | 10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
NM | White Clover Markets | 10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
NM | White Clover Markets | 10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
US$ 20.550,10 |
In this sample a new line was added to display the summary. Another option is to use the footer row to display the summary instead of creating a new one. When a new row is added to the grid, only the required cells to display the summarized columns are created. Using the footer, all the cells are created. In case of group summaries, generation of all cells or only the needed cells is a group attribute.
Now we will create a group. The code is shown below:
{
GridViewHelper helper = new GridViewHelper(this.GridView1);
helper.RegisterGroup("ShipRegion", true, true);
helper.ApplyGroupSort();
}
The first parameter of RegisterGroup method defines the columns to which the group must be created. It's also possible to create a composite group, consisting of an array of columns. The second parameter specifies if the group is automatic. In this case a new row will be created automatically for the group header. The third parameter specifies if the group columns must be hidden. The ApplyGroupSort method sets the sort expression of the grid as being the group columns, in this case, ShipRegion. This is required to grouping works properly, except if the data comes ordered from database.
In the above sample the column ShipRegion have been hidden:
ShipName | OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|---|
NM | |||||
Old World Delicatessen | 10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
Old World Delicatessen | 10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
Old World Delicatessen | 10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
Old World Delicatessen | 10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
Old World Delicatessen | 10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
White Clover Markets | 10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
White Clover Markets | 10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
White Clover Markets | 10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
OR | |||||
Save-a-lot Markets | 10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
Save-a-lot Markets | 10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
Save-a-lot Markets | 10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
Gourmet Lanchonetes | 10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
Split Rail Beer & Ale | 10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
Split Rail Beer & Ale | 10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
Lazy K Kountry Store | 10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
Let's make something more interesting, let's add a summary to the created group. We need just one more line to register the summary to the group:
{
GridViewHelper helper = new GridViewHelper(this.GridView1);
helper.RegisterGroup("ShipRegion", true, true);
helper.RegisterSummary("ItemTotal", SummaryOperation.Sum, "ShipRegion");
helper.ApplyGroupSort();
}
This time, the RegisterSummary method takes another parameter. The parameter specifies the name of the group to which the summary must be created. Group name is automatically generated from the group column names. If the group has only one column, group name will be the name of that column. If the group has more than one column, the group name will be the ordered concatenation of the columns that composes the group, joined with a plus sign ("+"): "ShipRegion+ShipName".
We can see below the grid with grouping and a summary for the group:
ShipName | OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|---|
NM | |||||
Old World Delicatessen | 10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
Old World Delicatessen | 10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
Old World Delicatessen | 10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
Old World Delicatessen | 10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
Old World Delicatessen | 10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
White Clover Markets | 10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
White Clover Markets | 10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
White Clover Markets | 10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
US$ 18.465,10 | |||||
OR | |||||
Save-a-lot Markets | 10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
Save-a-lot Markets | 10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
Save-a-lot Markets | 10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
Gourmet Lanchonetes | 10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
Split Rail Beer & Ale | 10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
Split Rail Beer & Ale | 10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
Lazy K Kountry Store | 10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
US$ 2.085,00 |
It's possible to create more than one group in the grid, simulating a hierarchical grouping, as seen below:
{
GridViewHelper helper = new GridViewHelper(this.GridView1);
helper.RegisterGroup("ShipRegion", true, true);
helper.RegisterGroup("ShipName", true, true);
helper.ApplyGroupSort();
}
Result:
OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|
NM | ||||
Old World Delicatessen | ||||
10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
White Clover Markets | ||||
10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
OR | ||||
Lazy K Kountry Store | ||||
10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
Gourmet Lanchonetes | ||||
10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
Split Rail Beer & Ale | ||||
10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
Save-a-lot Markets | ||||
10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
Visualization is compromised when there is more than one group. GridViewHelper has events to allow easy implementation of visual or functional adjusts. The list of events follows below:
GroupStart | Occurs when a new group starts, it means, when new values are found in the group column. |
GroupEnd | Occurs in the last row of the group |
GroupHeader | Occurs when an automatic header row is added for the group. The event is not triggered if the group is not automatic. |
GroupSummary | Occurs when the summary row is generated for the group. The event is not triggered if the group is not automatic, but will be triggered if the group is a suppression group (will be seen later on). |
GeneralSummary | Occurs after the general summaries be calculated. If the summary is automatic the event occurs after the summary row be added and after the summary values be placed in the row. |
FooterDataBound | Occurs in the footer databinding. |
With a few more lines of code we can improve the visual aspect of the grid:
{
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;
}
}
The grid after the cosmetics:
OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|
NM | ||||
Old World Delicatessen | ||||
10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
White Clover Markets | ||||
10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
OR | ||||
Lazy K Kountry Store | ||||
10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
Gourmet Lanchonetes | ||||
10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
Split Rail Beer & Ale | ||||
10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
Save-a-lot Markets | ||||
10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
More grouping options
There are two more interesting samples. The first presents a composite group. The second defines a suppress group, that has the same behavior of the sql GROUP BY clause. The repeating values are suppressed, and a summary operation is performed on the other columns.
Below we can see the code and the grid appearance for the composite group:
{
GridViewHelper helper = new GridViewHelper(this.GridView1);
string[] cols = new string[2];
cols[0] = "ShipRegion";
cols[1] = "ShipName";
helper.RegisterGroup(cols, true, true);
helper.ApplyGroupSort();
}
OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|
NM - Old World Delicatessen | ||||
10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
NM - White Clover Markets | ||||
10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
OR - Lazy K Kountry Store | ||||
10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
OR - Gourmet Lanchonetes | ||||
10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
OR - Split Rail Beer & Ale | ||||
10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
OR - Save-a-lot Markets | ||||
10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
We can add a summary to the group. This time we will define an average operation and add a label to indicate the operation:
{
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";
}
OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|
NM - Old World Delicatessen | ||||
10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
Average | US$ 3.422,30 | |||
NM - White Clover Markets | ||||
10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
Average | US$ 451,20 | |||
OR - Lazy K Kountry Store | ||||
10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
Average | US$ 108,00 | |||
OR - Gourmet Lanchonetes | ||||
10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
Average | US$ 155,00 | |||
OR - Split Rail Beer & Ale | ||||
10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
Average | US$ 561,00 | |||
OR - Save-a-lot Markets | ||||
10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
Average | US$ 233,33 |
The last sample will create a suppress group. It's important to mention that if a suppress group is defined, no other group may be created. In the same way, if there is already a group defined, we can't create a suppress group and an exception will be raised if we try it.
Below we can see the code and the grid appearance for the suppress group:
{
GridViewHelper helper = new GridViewHelper(this.GridView1);
helper.SetSuppressGroup("ShipName");
helper.RegisterSummary("Quantity", SummaryOperation.Sum, "ShipName");
helper.RegisterSummary("ItemTotal", SummaryOperation.Sum, "ShipName");
helper.ApplyGroupSort();
}
ShipRegion | ShipName | OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|---|---|
Lazy K Kountry Store | 9 | US$ 108,00 | ||||
Gourmet Lanchonetes | 20 | US$ 155,00 | ||||
Old World Delicatessen | 147 | US$ 17.111,50 | ||||
White Clover Markets | 59 | US$ 1.353,60 | ||||
Split Rail Beer & Ale | 66 | US$ 1.122,00 | ||||
Save-a-lot Markets | 33 | US$ 700,00 |
No value is displayed for the columns that don't have a summary operation defined. This makes sense because GridViewHelper doesn't know how to proceed to summarize the values found in the group rows to a unique value. This reminds the certain known message:
"Column 'column_name' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause."
It doesn't make sense to display the columns that don't have a summary operation, and to hide them we need to call a method:
{
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();
}
I know, it's a big big name! The resulting grid can be seen below:
ShipName | Quantity | ItemTotal |
---|---|---|
Lazy K Kountry Store | 9 | US$ 108,00 |
Gourmet Lanchonetes | 20 | US$ 155,00 |
Old World Delicatessen | 147 | US$ 17.111,50 |
White Clover Markets | 59 | US$ 1.353,60 |
Split Rail Beer & Ale | 66 | US$ 1.122,00 |
Save-a-lot Markets | 33 | US$ 700,00 |
Summary operations
GridViewHelper has 3 built-in summary operations: sum, average and row count. A very useful feature is the possibility of define custom summary operations. To achieve this we need to provide two methods to the GridViewHelper. A method will be called for each row found in the grid (or group) and the other will be called to retrieve the result of the summary operation. Below we have a sample of a custom summary operation. The semi-dummy operation will return the minimum value found:
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];
}
In the code above we can see the required methods signatures. Both receive the summarized group and column names. If the summary is not relative to a group, the group parameter will be null. The method that is called for each row found in the grid, receives also the value of the column in the current row.
The resulting grid can be seen below :
ShipRegion | ShipName | OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|---|---|
NM | Old World Delicatessen | 10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
NM | Old World Delicatessen | 10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
NM | Old World Delicatessen | 10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
NM | Old World Delicatessen | 10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
OR | Save-a-lot Markets | 10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
OR | Save-a-lot Markets | 10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
OR | Save-a-lot Markets | 10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
OR | Gourmet Lanchonetes | 10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
OR | Split Rail Beer & Ale | 10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
OR | Split Rail Beer & Ale | 10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
OR | Lazy K Kountry Store | 10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
NM | Old World Delicatessen | 10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
NM | White Clover Markets | 10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
NM | White Clover Markets | 10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
NM | White Clover Markets | 10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
4 |
Limitations
In one sample we said that we can simulate a hierarchical grouping. Although the grid appears to present a hierarchical grouping, the actual implementation isn't hierarchical. There's no group or subgroup. There are only sequentially registered groups. This becomes a problem if we need to create a summary for an inner group. Below we can see what happens in this situation:
{
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] + " ]";
}
OrderId | ProductName | Quantity | UnitPrice | ItemTotal |
---|---|---|---|---|
NM | ||||
Old World Delicatessen | ||||
10922 | Alice Mutton | 15 | US$ 39,00 | US$ 585,00 |
10922 | Teatime Chocolate Biscuits | 35 | US$ 4,50 | US$ 157,50 |
10925 | Inlagd Sill | 25 | US$ 19,00 | US$ 475,00 |
10925 | Filo Mix | 12 | US$ 7,00 | US$ 84,00 |
10981 | Côte de Blaye | 60 | US$ 263,50 | US$ 15.810,00 |
[ Summary for ShipName Old World Delicatessen ] | US$ 17.111,50 | |||
White Clover Markets | ||||
10989 | Grandma's Boysenberry Spread | 40 | US$ 25,00 | US$ 1.000,00 |
10989 | Queso Cabrales | 15 | US$ 21,00 | US$ 315,00 |
10989 | Camembert Pierrot | 4 | US$ 9,65 | US$ 38,60 |
OR | ||||
[ Summary for ShipName White Clover Markets ] | US$ 1.353,60 | |||
Lazy K Kountry Store | ||||
10969 | Spegesild | 9 | US$ 12,00 | US$ 108,00 |
[ Summary for ShipName Lazy K Kountry Store ] | US$ 108,00 | |||
Gourmet Lanchonetes | ||||
10959 | Rhönbräu Klosterbier | 20 | US$ 7,75 | US$ 155,00 |
[ Summary for ShipName Gourmet Lanchonetes ] | US$ 155,00 | |||
Split Rail Beer & Ale | ||||
10961 | Filo Mix | 6 | US$ 7,00 | US$ 42,00 |
10961 | Lakkalikööri | 60 | US$ 18,00 | US$ 1.080,00 |
[ Summary for ShipName Split Rail Beer & Ale ] | US$ 1.122,00 | |||
Save-a-lot Markets | ||||
10935 | Chai | 21 | US$ 18,00 | US$ 378,00 |
10935 | Carnarvon Tigers | 4 | US$ 62,50 | US$ 250,00 |
10935 | Tunnbröd | 8 | US$ 9,00 | US$ 72,00 |
[ Summary for ShipName Save-a-lot Markets ] | US$ 700,00 | |||
US$ 20.550,10 |
As we can see, the summary is created after the header of the outer group. This occurs because the event sequence is:
Group1_Start
Group1_End
Group2_Start
Group2_End
To a hierarchical grouping, the event sequence should be:
Group1_Start
Group2_Start
Group2_End
Group1_End
Implementation
GridViewHelper was implemented as a standalone class instead of an inherited class. This makes possible to use the GridViewHelper with any GridView, and doesn't force the developer to inherit a specific GridView, what could affect the classes design. There's another four classes in the solution: GridViewSummary, GridViewGroup, GridViewSummaryList and GridViewGroupList. The "list" classes were created to allow access by a string indexer: helper.GeneralSummaries["ItemTotal"].Value.
When the GridViewHelper is created, a reference to the target GridView is saved, and the RowDataBound event is bound to the method that does the hard work:
{
this.mGrid = grd;
this.useFooter = useFooterForGeneralSummaries;
this.groupSortDir = groupSortDirection;
this.mGeneralSummaries = new GridViewSummaryList();
this.mGroups = new GridViewGroupList();
this.mGrid.RowDataBound += new GridViewRowEventHandler(RowDataBoundHandler);
}
Some methods used internally by the GridViewHelper were defined public because they provide some useful features that may be needed for some customizations. There are a few other options that wasn't shown in the samples but that can be easily verified with Visual Studio intellisense.
GridView使用【GridViewHelper】分组统计相关推荐
- sql server 经典SQL——分组统计
一.分组统计 数据 name dtdate result aa 2017-01-04 1 aa 2017-01-04 1 aa 2017-01-05 1 aa 2017-01-05 0 bb 2017 ...
- pandas使用groupby函数对dataframe进行分组统计、使用as_index参数设置分组聚合的结果中分组变量不是dataframe的索引(index)
pandas使用groupby函数对dataframe进行分组统计.使用as_index参数设置分组聚合的结果中分组变量不是dataframe的索引(index) 目录
- R语言进行数据聚合统计(Aggregating transforms)计算滑动窗口统计值(Window Statistics):使用R原生方法、data.table、dplyr等方案、计算滑动分组统计
R语言进行数据聚合统计(Aggregating transforms)计算滑动窗口统计值(Window Statistics):使用R原生方法.data.table.dplyr等方案.计算滑动分组统计 ...
- Elasticsearch Aggregation 多个字段分组统计 Java API实现
2019独角兽企业重金招聘Python工程师标准>>> 现有索引数据: index:school type:student ----------------------------- ...
- mysql 按小时分组统计_PowerBI业务分析:按排名分组统计
对数据进行分组统计是常用的一种分析方式,之前的文章中曾介绍了按照客户订单数量进行分组统计,Power BI 数据分析应用:客户购买频次分布这篇文章介绍一下PowerBI如何按照客户的排名进行分组统计, ...
- Oracle之数据操作__分组统计查询
一. 统计函数 1. COUNT(*),COUNT(字段),COUNT(DISTNCT 字段) SELECT COUNT(*),COUNT(ename),COUNT(comm),COU ...
- 问题 B: 分组统计
分组统计 问题 B: 分组统计时间限制: 1 Sec 内存限制: 32 MB 提交: 416 解决: 107 [提交][状态][讨论版][命题人:外部导入] 题目描述 先输入一组数,然后输入其分组,按 ...
- 记录一下pandas的分组统计功能,agg
主要是记录一下pandas学习,最近要统计一个数据,我向以前stata里面有一个很好用的函数,就是tabstat,可以分组统计,并且输出很多指标. 最近处理数据我的数据是这样的. 我向按照 valid ...
- mysql十分钟分组_MYSQL每隔10分钟进行分组统计的实现方法
前言 本文的内容主要是介绍了mysql每隔10分钟进行分组统计的实现方法,在画用户登录.操作情况在一天内的分布图时会非常有用,之前我只知道用「存储过程」实现的方法(虽然执行速度快,但真的是太不灵活了) ...
- linux awk 分组统计
1.awk分组统计 cat order.txt | awk 'NR>=2{a[$3]+=$4}END{for(j in a) print j, a[j]}' | sort -rk 2 | hea ...
最新文章
- R语言应用str_match函数和str_match_all函数从字符串抽取匹配的字符串模式:str_match函数抽取第一个匹配的字符串模式、str_match_all函数抽取多个匹配的字符串模式
- 【T10】记住,TCP__IP不是轮询的
- 《淘宝网开店 拍摄 修图 设计 装修 实战150招》一一1.17 如何选择合适的拍摄地点...
- 移动界面设计点滴:工欲善其事,必先利其器[转]
- 机器人动力学方程的性质
- 【JS 逆向百例】cnki 学术翻译 AES 加密分析
- Linux下的tar压缩解压缩命令详解(转)
- 在…视域下是什么意思_电影中出现的出品人是什么意思?你需要了解下
- python 字符串方法
- 年轻人创业可以选择的3个方向
- 奚江华的几篇Silverlight文章
- 本题要求编写程序,先将输入的一系列整数中的最小值与第一个数交换,然后将最大值与最后一个数交换,最后输出交换后的序列
- mr.baidu.com百度官方缩短网址接口网站调用生成制作方法解析
- CodeForces 19E 仙女fairy
- java实现随机生成五位 或 六位/新能源车牌号
- 电路及电路设计经验技巧大合集
- 【Elasticsearch源码】CCR源码分析(一)
- 计算机音乐制作旋律教学,电脑音乐制作走进课堂-520吉他网
- 浙大教务网登录验证码自动填充--chrome插件开发
- vue/cli4 单元测试与覆盖率体系搭建
热门文章
- java dcm转bmp源码_DCM文件转图像,并高清处理图像
- python初体验-hello world答案_Python初体验(一)—【配置环境变量】【变量】【input】【条件语句】【循环语句】...
- python字符串的内部函数_「Python」字符串操作内置函数
- core修改模型属性中的默认单位
- Linux的zip压缩文件压缩和解压
- MAC苹果电脑关闭系统完整性保护SIP(System Integrity Protection)
- 2022最火土味情话文案
- android+双卡imei,以编程方式在Android中为双SIM卡检索IMEI号码
- Arduino Mega/Uno制作宏定义键盘(不需刷firmware!!)
- linux下好玩的文本工具-figlet