数据报表开发技巧:自动为数据报表添加【小计】、【总计】行

摘要:
在开发ERP系统的数据报告时,几乎需要看到这样的汇总数据。在数据报告的显示列表中,底行通常是或的摘要行。因此,如果您可以为每个数据报告自动添加和汇总行,那么将节省大量的开发时间。

  在开发ERP系统的数据报表时,几乎都是需要看到【小计】、【总计】这样的汇总数据的,在数据报表的显示列表中,最下面的一行通常就是【小计】或者【总计】的汇总行。如果手动为每个报表都增加汇总行,那也是一份不小的工作量。

  所以,如果能自动为每个数据报表自动添加【小计】、【总计】汇总行,那将可以节省不少的开发时间。本文将给出实现这种方案的思路原理以及源码。

  本文中,报表数据的显示使用的是WinForm的DataGridView控件,如果是Web项目,其原理和思路是一样的。

  举个栗子,零售店POS机上查询销售单的效果如下图所示:

  数据报表开发技巧:自动为数据报表添加【小计】、【总计】行第1张

  在报表的最下面有一行【总计】,对数量和金额项进行了汇总。

  下面,我们来详细讲解是如何自动为其添加【总计】这一汇总行的。

一.基本原理

1.一般而言,数据报表的现实的核心数据是DataGridView绑定的一个列表List<T>,每一个T对象对应着报表中的一行数据。

2.在数据报表中,【小计】、【总计】所对应的汇总行与上面列表中的其它普通行,是有区别的,所以,它们对应的T对象也是有区别的。

3.我们通过T的一个名为 IsStatistics 的bool属性来区别普通行与汇总行。如果IsStatistics为true,表示其对应的行就为汇总行。

4.为了达到上面描述的这一目的,我们让T必须实现接口IStatisticabled这个接口。

    public interface IStatisticabled
    {
        bool IsStatistics { set; get; }
    }

5.为报表添加汇总行,实际上就是向List<T>列表中添加一个 IsStatistics 为true的 T 对象。

6.然后,通过反射来统计需要汇总的那些项(即T的某些属性),然后将汇总得到的结果赋值给汇总T对象对应的属性。

7.在绑定到DataGridView时,通过判断列表中 T 对象的IsStatistics属性,如果为true,就将该行Row对应的RowHeader的文本设置为【小计】或【总计】。

二.思路实现

  就上面描述的思路来看,稍微有点难度的地方在于最后两点,下面我们就详细讲解一下。

1.为List<T>增加汇总行

  增加汇总行,所用到的主要技术就是反射Relection。

    /// <summary>
    /// 为数据报表增加一个汇总行。
    /// </summary>
    /// <typeparam name="T">报表记录对象的类型</typeparam>
    /// <param name="list">数据行对象列表</param>
    /// <param name="statColumns">需要进行统计的列</param>
    public static void AddSumRow<T>(List<T> list ,params string[] statColumns) where T :IStatisticabled, new()
    {
        T sum = new T();
        sum.IsStatistics = true;

        foreach (string column in statColumns) //针对每一个汇总项
        {
            double total = 0;
            foreach (T t in list) //统计
            {
                object val = ReflectionHelper.GetProperty(t, column);
                total += double.Parse(val.ToString());
            }
            object newTotal = TypeHelper.ChangeType(typeof(T).GetProperty(column).PropertyType, total);
            ReflectionHelper.SetProperty(sum, column, newTotal);
        }
        list.Add(sum);
    }

(1)为了可以动态new一个统计行,必须要让T有 new() 这个约束。

(2)将统计行的 IsStatistics 标记设置为true。

(3)针对每一个统计项进行统计:通过反射拿到每一行该项的属性值,并转换成double类型(因为double兼容了所有的数值类型),进行累加,然后将累加的结果转换成正确的类型,最后,赋值给统计行对应的属性。

(4)将统计行添加到list列表中,作为最后一个对象。

2.绑定到DataGridView 

    List<RetailOrder> list = this.GetOrderList();
    AddSumRow(list, new string[] { "Count", "Money" });
    this.dataGridView1.DataSource = list;

    DataGridViewCellStyle style = new DataGridViewCellStyle();
    style.Font = new Font(this.dataGridView1.DefaultCellStyle.Font.Name, this.dataGridView1.DefaultCellStyle.Font.Size, FontStyle.Bold);

    this.dataGridView1.RowHeadersDefaultCellStyle = style;
    this.dataGridView1.Rows[list.Count - 1].HeaderCell.Value = "总计";
    this.dataGridView1.Rows[list.Count - 1].DefaultCellStyle = style;  

(1)通过GetOrderList方法获取到销售单列表后,我们通过AddSumRow方法为其添加一个汇总行,并对【Count】、【Money】进行汇总。

(2)将包含了汇总行的列表绑定到DataGridView。

(3)将最后一行的RowHeader的Cell的value设置为【总计】 。

(4)将【总计】行的所有数据显示都变成粗体。

三.示例源码下载

1.本文Demo源码:DataReportsSample.rar

2.该Demo中用到了ESBasic的反射帮助类ReflectionHelper,这里可以下载我的开源基础类库:ESBasic 源码

四.后续功能

    本文示例是一个【小计】、【总计】汇总功能的基础展示,实际应用中,通常还会牵涉到以下问题:

(1)当报表数据存在分页时,一般会同时存在【小计】、【总计】行,【小计】是本页的汇总,【总计】是所有业的汇总。

(2)当DataGridView绑定的某些列对应着Entity的某个只读属性,并且这个只读属性不会返回null和string.Empty时,汇总行的这一列就会有文字显示(这是一个非汇总行,目标单元格应该是空的),要如何处理?

(3)当DataGridView的某一些是一个操作列,即对应着DataGridViewLinkColumn,如果让汇总行的目标单元格中不出现Link,而是留空了?

(4)有些数据的汇总,可能是要进行绝对值的汇总,那又该如何处理?

         这些问题,我们都将在下篇文章的示例中一并解决,敬请期待。

免责声明:文章转载自《数据报表开发技巧:自动为数据报表添加【小计】、【总计】行》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇uniapp app-plus pages.jsonC#中生成随机数的几种方法下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

listview 设置数组为空

listview.setEmpty(View view); 使用listView或者gridView时,当列表为空时,有时需要显示一个特殊的empty view来提示用户,今日对这个方法进行一下小结,书写的方式有三种: 1.一般情况下,继承ListActivity,只要 <ListView android:id="@id/android:list"...

phpCB 批量格式化php文件 经典方法

发现phpCB整理php文档非常好,但有个缺点是不能批量处理,使用过程中发现phpCB是一个CMD程 序。于是想到php的system函数调用cmd。将phpCB放到 系统文件夹 system下。 下面是phpCB批量转换的php程序: <? header ( "Content-type: text/html; charset=gb2312" ) ;...

java 线程池的用法

1.java自带的类ExecutorService用于提供线程池服务,可以一下方法初始化线程池: ExecutorService pool = Executors.newFixedThreadPool(5);//固定线程的线程池 ExecutorService pool = Executors.newCachedThreadPool();//具有伸缩...

Linux下查看Nginx的并发连接数和连接状态-乾颐堂

Linux下查看Nginx等的并发连接数和连接状态。 1、查看Web服务器(Nginx Apache)的并发请求数及其TCP连接状态:  netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 或者: netstat -n | awk '/^tcp/ {++state[$NF...

Flutter——数组以符号隔开转字符串

///数组转字符串 String getTaskScreen(List list){ List tempList =List(); String str = ''; list.forEach((f){ tempList.add(f.title); }); tempList.forEach((f){...

Json与List的相互转换

问题由来: 最近由于做一个项目,项目的一个功能就是根据Listview的内容生成一个二维码,然后扫描二维码获取list,再重新显示listview。 核心就是: list—->生成二维码——>获取二维码—–>获取list 生成二维码的方法: http://blog.csdn.net/demonliuhui/article/details/...