數據報表開發技巧:自動爲數據報表添加【小計】、【總計】行

  在開發ERP系統的數據報表時,幾乎都是須要看到【小計】、【總計】這樣的彙總數據的,在數據報表的顯示列表中,最下面的一行一般就是【小計】或者【總計】的彙總行。若是手動爲每一個報表都增長彙總行,那也是一份不小的工做量。html

  因此,若是能自動爲每一個數據報表自動添加【小計】、【總計】彙總行,那將能夠節省很多的開發時間。本文將給出實現這種方案的思路原理以及源碼。this

  本文中,報表數據的顯示使用的是WinForm的DataGridView控件,若是是Web項目,其原理和思路是同樣的。spa

  舉個栗子,零售店POS機上查詢銷售單的效果以下圖所示:code

  

  在報表的最下面有一行【總計】,對數量和金額項進行了彙總。orm

  下面,咱們來詳細講解是如何自動爲其添加【總計】這一彙總行的。htm

 

一.基本原理

1.通常而言,數據報表的現實的核心數據是DataGridView綁定的一個列表List<T>,每個T對象對應着報表中的一行數據。對象

2.在數據報表中,【小計】、【總計】所對應的彙總行與上面列表中的其它普通行,是有區別的,因此,它們對應的T對象也是有區別的。blog

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)有些數據的彙總,多是要進行絕對值的彙總,那又該如何處理?

         這些問題,咱們都將在下篇文章的示例中一併解決,敬請期待。

相關文章
相關標籤/搜索