PivotGridControl自定义行数据的统计公式

发布时间 2023-09-14 22:42:01作者: 此坑已满

我们在使用PivotGridControl进行数据统计的时候,用时候需要在不同的行使用不同的汇总公式的情况,本文就是为了说明怎么实现此功能,如下图说明

 

数据源:

 

注意:此时数据列指定的SummaryType设置的是Sum;并且数据列指定了为double类型

 

 

SummaryType指定的几种聚合函数,Max、Min、Count适用于所有类型,只有数字类型可以适配所有聚合函数

 

以上示例很明显的错误:在GrandTotal列,成功数和总数直接使用求和的公式没有问题,但是成功率也使用求和的公式就出现了问题。

根据这样的场景在成功率这一行,必须使用的是总成功数/总总数的公式。这就需要在指定的行实现自定义的公式。

 

那么怎么实现这样的功能呢?

  1. 将数据字段的SummaryType设置为Custom

 

2.创建CustomSummary事件(这个事件是在创建每一个单元格的时候会调用的事件,此时可以直接修改计算的公式和显示的值)

 3.实现CustomSummary事件

 

为了减少逻辑复杂度,此处设置数据类型、数据、日期三个字段不可拖动;班次可以拖动,但是只能作为FilterArea或者RowArea

在这样的情况下,原始数据可以不用计算成功率,改为在CustomSummary事件中计算

 

CustomSummary实现代码如下所示

private void pivotGridControl1_CustomSummary(object sender, DevExpress.XtraPivotGrid.PivotGridCustomSummaryEventArgs e)

        {

            if (e.DataField != pivotGridField2)

            {

                //因为需要计算的是数据字段,所以如果此时的DataField不是数据字段时,则直接返回,不执行任何操作

                return;

            }

            //只有行数据为成功率%的时候,需要计算自定义显示的数据

            if (e.RowField != null && e.RowFieldValue.ToString() == "成功率%")

            {

                //如果当前列字段不为空,则表示当前时Grand Total列

                //也可以按照下面的写法,代表如果时日期列的时候

                //if(e.ColumnFieldValue.ToString()=="日期")

                if (e.ColumnField != null)

                {

                    //此时也需要分为两种情况,一种时班次在FilterArea的时候,另外一种是班次在RowArea的时候

                    //因为当在RowArea的时候,每一行数据只对应唯一的一种班次,但是在FilterArea的时候还需要能够计算同时选中白班和夜班的情况

                    if (pivotGridField4.Area == PivotArea.FilterArea)

                    {

                        PivotDrillDownDataSource pds = e.CreateDrillDownDataSource();//获取当前单元格所关联的数据

                        //此处的实现有更加规范统一的方法,此处仅作为示例,所以简化了逻辑,并使用了更为固定的实现方式,不够灵活

                        string[] sV = pivotGridField4.GetAvailableValues().Select(t => t.ToString()).ToArray();//获取到选中的班次

                        string cd = pds.GetValue(0, "日期").ToString();//获取当前行的日期数据

                        //因为每一个分组的数据即可能变更Area,同时还可能展开和合并,此时pds就会有多行数据,这里的代码为了简化,只作为一个示例程序,因此没有

                        //写出这些逻辑,如果有兴趣可以自己去实现相关功能

        //注意此处用的datas数据类型为List,主要为了简化代码,直接使用Linq,因为PivotGridControl的DataSource属性只支持DataSet和DataTable这种类型

                        double okNum = datas.Where(t => sV.Any(v => v == t.班次) && t.数据类型 == "成功数" && t.日期 == cd).Select(t => t.数据).Sum();

                        double toNum = datas.Where(t => sV.Any(v => v == t.班次) && t.数据类型 == "总数" && t.日期 == cd).Select(t => t.数据).Sum();

                        e.CustomValue = Math.Round(okNum / toNum * 100, 2);

                    }

                    else

                    {

                        PivotDrillDownDataSource pds = e.CreateDrillDownDataSource();

                        string ct = pds.GetValue(0, "班次").ToString();

                        string cd = pds.GetValue(0, "日期").ToString();

                        double okNum = datas.Where(t => t.班次 == ct && t.数据类型 == "成功数" && t.日期 == cd).Select(t => t.数据).Sum();

                        double toNum = datas.Where(t => t.班次 == ct && t.数据类型 == "总数" && t.日期 == cd).Select(t => t.数据).Sum();

                        e.CustomValue = Math.Round(okNum / toNum * 100, 2);

                    }

                }

                else

                {

                    if (pivotGridField4.Area == PivotArea.FilterArea)

                    {

                        PivotDrillDownDataSource pds = e.CreateDrillDownDataSource();

                        string[] sV = (string[])pivotGridField4.GetAvailableValues().Select(t => t.ToString()).ToArray();

                        //如果是统计列,则不需要指定具体日期,而是需要统计出所有日期的数据

                        double okNum = datas.Where(t => sV.Any(v => v == t.班次) && t.数据类型 == "成功数").Select(t => t.数据).Sum();

                        double toNum = datas.Where(t => sV.Any(v => v == t.班次) && t.数据类型 == "总数").Select(t => t.数据).Sum();

                        e.CustomValue = Math.Round(okNum / toNum * 100, 2);

                    }

                    else

                    {

                        PivotDrillDownDataSource pds = e.CreateDrillDownDataSource();

                        string ct = pds.GetValue(0, "班次").ToString();

                        double okNum = datas.Where(t => t.班次 == ct && t.数据类型 == "成功数").Select(t => t.数据).Sum();

                        double toNum = datas.Where(t => t.班次 == ct && t.数据类型 == "总数").Select(t => t.数据).Sum();

                        e.CustomValue = Math.Round(okNum / toNum * 100, 2);

                    }

                }

            }

            else

            {

                e.CustomValue = e.SummaryValue.Summary;//其他的字段则使用求和公式即可

            }

        }

结果如下:

班次在RowArea的时候

 

班次倍拖动到FilterArea的时候