zoukankan      html  css  js  c++  java
  • DevExpress GridView.CustomSummaryCalculate 实现自定义Group Summary

    --首发于博客园, 转载请保留链接  博客原文

    DevExpress Documentation官方地址:GridView.CustomSummaryCalculate Event

    1. 概要

    界面上 GridView 显示的数据里某些字段在读出来的时候已经 SUM By FieldA ,在界面上统计时就不能简单累计总和,条件是 FieldA 相同不能重复相加。

    2. 问题

    view SalesOrderLineList 中,RealTimeStockTotalQuantity 与 RealTimeProductionTotalQuantity 分别是每个 ItemID 的总库存量 与 正在生产的总量

    那么在 SalesOrderLineList 的 GridControl 中

    (1) 当 Group By Item 时, Group Footer 只须取其中一行

    (2) Grid Footer 中,应该是所有 ItemID 对应的 库存量总和

    (3) 当 Group By 不是 Item 时,Group Footer 可不显示

    一般来说,页脚统计多为 Sum, Count, Average 这样的 SummaryType, 用于直接在 GridColumn SummaryItem.SummaryType 选择相应的选择,无须特殊处理。

    对于 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 或其他数据源类型显然是要另外处理的。

  • 相关阅读:
    Log4j,Log4j2,logback,slf4j日志学习(转)
    MultipartFile类
    @Transactional(转)
    redis序列化和反序列化
    redis常见问题(转)
    为什么说Redis是单线程的以及Redis为什么这么快!(转)
    Numpy 用法小结
    正则表达式使用小结
    Hive 窗口函数、分析函数
    Hive UDF开发实例学习
  • 原文地址:https://www.cnblogs.com/EasyInvoice/p/3892136.html
Copyright © 2011-2022 走看看