DevExpress GridView.CustomSummaryCalculate 實現自定義Group Summary

--首發於博客園, 轉載請保留連接  博客原文html

DevExpress Documentation官方地址:GridView.CustomSummaryCalculate Eventexpress

 

1. 概要

界面上 GridView 顯示的數據裏某些字段在讀出來的時候已經 SUM By FieldA ,在界面上統計時就不能簡單累計總和,條件是 FieldA 相同不能重複相加。this

2. 問題

view SalesOrderLineList 中,RealTimeStockTotalQuantity 與 RealTimeProductionTotalQuantity 分別是每一個 ItemID 的總庫存量 與 正在生產的總量spa

那麼在 SalesOrderLineList 的 GridControl 中3d

(1) 當 Group By Item 時, Group Footer 只須取其中一行code

(2) Grid Footer 中,應該是全部 ItemID 對應的 庫存量總和orm

(3) 當 Group By 不是 Item 時,Group Footer 可不顯示htm

通常來講,頁腳統計多爲 Sum, Count, Average 這樣的 SummaryType, 用於直接在 GridColumn SummaryItem.SummaryType 選擇相應的選擇,無須特殊處理。blog

對於 RealTimeStockTotalQuantity 與 RealTimeProductionTotalQuantity 這樣特殊的統計字段只能在代碼實現計算邏輯。事件

3. 效果圖

以下:

4. 思路

把 ItemID 相關的統計字段保存到本地的 Dictionary 裏面,key 爲 ItemID, value 爲 相關字段數據,

而後在 GridView.CustomSummaryCalculate 事件中取累計值 賦給 TotalSummary,取對應 ItemID 的值賦給 GroupSummary 。

因爲字段較多(實際中不止2個統計字段),定義一個類 ItemSummaryInfo,以下:

private class ItemSummaryInfo
{
    public int ItemID { get; set; }
 
    public int RealTimeProductionTotalQuantity { get; set; } 
    public int RealTimeStockTotalQuantity { get; set; }
 
    public decimal RealTimeProductionTotalWeight { get; set; }
    public decimal RealTimeStockTotalWeight { get; set; }
    public int RTProductionInProcessQuantity { get; set; }
    public int RTProductionActiveQuantity { get; set; }
    public int RTProductionPParcelsQuantity { get; set; }
 
    public object this[string propertyName]
    {
        get { return Prop(propertyName).GetValue(this, null); }
        set { Prop(propertyName).SetValue(this, value, null); }
    }
 
    System.Reflection.PropertyInfo Prop(string propertyName)
    {
        return this.GetType().GetProperty(propertyName);
    }
}

 

5. 實現過程

5.1 GridView 中添加 字段 RealTimeProductionTotalQuantity , RealTimeStockTotalQuantity

字段屬性 SummaryItem.SummaryType = Custome,不然 Grid 頁腳沒法顯示

 

5.2 在 GridView 的 Group Summary Items 裏添加 相關的 Group Summary

主要 ShowInGroupColumnFooter 是 Step 1 中添加的對應字段, SummaryType 仍爲 Custom

 

 5.3 GridView.DataSourceChanged 之類的事件裏提取最新據保存到本地變量 _itemSums

void SalesOrderLineListManager_DataSourceChanged(object sender, EventArgs e)
{
    RetreiveItemSummary();
}

private void RetreiveItemSummary()
{
    var gridvisibleColumnNames =
        from GridColumn column in grdViewMain.Columns
        where column.UnboundType == DevExpress.Data.UnboundColumnType.Bound && column.Visible
        select column.FieldName;

    // 隱藏字段不做處理,只處理顯示字段
    processNeededGroupFields = groupByItemFields.Intersect(gridvisibleColumnNames).ToArray();

    _itemSums = new Dictionary<int, ItemSummaryInfo>();

    DataTable dt = Manager.DataSource as DataTable;
    if (dt == null)
        return;

    #region retreive Item Group fields

    var groupByItem =
        from row in dt.AsEnumerable()
        group row by new { Item = row["ItemID"] } into grp
        select new
        {
            ItemID = (int)grp.Key.Item,
            Rows = grp
        };

    foreach (var item in groupByItem)
    {
        if (_itemSums.ContainsKey(item.ItemID))
            continue;

        ItemSummaryInfo newItem = new ItemSummaryInfo() { ItemID = item.ItemID };

        // 保存到 Dictionary<int, ItemSummaryInfo> 
        foreach (var groupfield in processNeededGroupFields)
        {
            if (groupByItemWeightFields.Contains(groupfield))
                newItem[groupfield] = (decimal)item.Rows.First()[groupfield];
            else
                newItem[groupfield] = (int)item.Rows.First()[groupfield];
        }

        _itemSums.Add(item.ItemID, newItem);
    }

    #endregion

    grdViewMain.RefreshData();
}

 

5.4 添加 GridView.CustomSummaryCalculate 事件,在 CustomSummaryProcess.Finalize 中顯示相關數據

void grdViewMain_CustomSummaryCalculate(object sender, DevExpress.Data.CustomSummaryEventArgs e)
{
    if (IDEHelper.DesignTime)
        return;

    GridView view = sender as GridView;
    string fieldName = (e.Item as GridSummaryItem).FieldName;
    int rowHandle = e.RowHandle;

    if (processNeededGroupFields == null || !processNeededGroupFields.Contains(fieldName) || rowHandle < 0)
        return;

    ResetItemGroupSummary();

    int itemId = 0;
    switch (e.SummaryProcess)
    {
        case CustomSummaryProcess.Start:
            break;

        case CustomSummaryProcess.Calculate:
            break;

        case CustomSummaryProcess.Finalize:

            if (e.IsTotalSummary)
            {
                if (groupByItemWeightFields.Contains(fieldName ))
                {
                    e.TotalValue = _itemSums.Sum(x => (decimal)x.Value[fieldName]);
                }
                else
                {
                    e.TotalValue = _itemSums.Sum(x => (int)x.Value[fieldName]);
                }
            }
            else if (e.IsGroupSummary)
            {
                if (isGroupByItemOnly)
                {
                    object id = view.GetRowCellValue(e.RowHandle, colItemID);
                    if (id == null) return;
                    itemId = (int)id;
                    if (!_itemSums.ContainsKey(itemId)) return;

                    e.TotalValue = _itemSums[itemId][fieldName];
                }                     
            }

            break;

        default:
            break;
    }

}
 
private void ResetItemGroupSummary()
{
    if (isPreviousGroupByItemOnly == isGroupByItemOnly)
        return;

    grdViewMain.GroupSummary.BeginUpdate();

    isPreviousGroupByItemOnly = isGroupByItemOnly;

    if (isGroupByItemOnly)
    {
        // add item group summary
        ItemGroupSummaryItem.ForEach(x =>
        {
            if (grdViewMain.GroupSummary.IndexOf(x) >= 0)
                return;
            grdViewMain.GroupSummary.Add(x);
        });
    }
    else
    {
        // remove item group summary
        ItemGroupSummaryItem.ForEach(x =>
        {
            if (grdViewMain.GroupSummary.IndexOf(x) >= 0)
                grdViewMain.GroupSummary.Remove(x);
        });
    }

    grdViewMain.GroupSummary.EndUpdate();
} 

 

5. 5 補充相關變量定義

// 保存 ItemID Group 數據
private Dictionary<int, ItemSummaryInfo> _itemSums = null;

// 當前須要處理字段
string[] processNeededGroupFields = null;

// 備份前一次 Group ItemID, 用於判斷是否須要移除/添加 Group SummaryID
bool isPreviousGroupByItemOnly {get;set;}

// GridView 是否 Group ItemID
bool isGroupByItemOnly { get { return grdViewMain.GroupCount == 1 && grdViewMain.GroupedColumns[0] == colItemID; } }

string[] groupByItemFields = new string[]{
    "RealTimeProductionTotalQuantity", 
    "RealTimeStockTotalQuantity",
    "RealTimeProductionTotalWeight",
    "RealTimeStockTotalWeight",
    "RTProductionInProcessQuantity",
    "RTProductionActiveQuantity",
    "RTProductionPParcelsQuantity",
};

string[] groupByItemWeightFields = new string[] {
    "RealTimeProductionTotalWeight",
    "RealTimeStockTotalWeight",
};

List<GridGroupSummaryItem> _itemGroupSummaryItems = null;

// 要處理的 Group Summary Item ,用於格式化以及GridView 添加/移除 的訪問
public List<GridGroupSummaryItem> ItemGroupSummaryItem
{
    get
    {
        if (_itemGroupSummaryItems == null)
        {
            _itemGroupSummaryItems = new List<GridGroupSummaryItem>();
            foreach (GridGroupSummaryItem summaryItem in grdViewMain.GroupSummary)
            {
                if (!groupByItemFields.Contains(summaryItem.FieldName))
                    continue;

                // synchronize displayformat
                summaryItem.DisplayFormat = summaryItem.ShowInGroupColumnFooter.DisplayFormat.GetFormatString();

                _itemGroupSummaryItems.Add(summaryItem);
            }
        }
        return _itemGroupSummaryItems;
    }
    set { _itemGroupSummaryItems = value; }
}

 

6. 總結

(1) 每次數據源發生變化時必須從新取值,不然顯示的數據有可能不許確

(2) 當 GroupBy 發生變化時,須要 移除/添加 GroupSummaryItem, 假設 GroupBy ItemID 不成立而沒有移除GroupSummaryItem,那麼 GroupFooter 會顯示一個空白方框,影響美觀

(3) ItemSummaryInfo 類中屬性 this[string propertyName] 根據屬性名訪問屬性,避免逐個屬性 Get / Set, 實現了簡化代碼

(4) 開始時在 CustomSummaryCalculate 事件中更新本地數據,CustomSummaryProcess.Start 時清空數據,CustomSummaryProcess.Calculate 時保存數據,官方文檔也傾向於這種方法,可是有一個侷限是每個 Field 都會分別跑 Start, Calculate, Finalize, 當要處理的字段比較多時,特別是數據記錄行較多,重複作 清除/保存 一樣的數據,重複讀寫,效率低下,所以選擇在數據源發生變化時讀寫一次,有利於提升效率,缺點是 數據源 限於 DataTable ,若是 是 Linq 或其餘數據源類型顯然是要另外處理的。

相關文章
相關標籤/搜索