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

Devexpress GridView.CustomSummaryCalculate 实现自定义Group Summary,布布扣,bubuko.com

时间: 2024-12-21 07:06:14

Devexpress GridView.CustomSummaryCalculate 实现自定义Group Summary的相关文章

DevExpress gridview下拉框repositoryItemComboBox的使用

本以为DevExpress gridview中的下拉框会像比原来的datatgridview中的下拉框绑定数据简单好用,没想到费了老大劲,查阅各种资料总算是绑定上了数据,并且能够实现想要的效果.下面就详细写一下这个实现的过程,分享一下,同时也是对这个知识再次熟悉一遍. 一.绑定前准备 这一部分基本上是一些基础的知识,但也有些地方要注意的. 1.添加下拉框列 在Grid Designer中,添加一列,在这列的ColumnEdit熟悉中,可以选择这列的编辑样式,比如让这列是一个按钮或者选择框等等,这

DevExpress GridView 那些事儿

1:去除 GridView 头上的 "Drag a column header here to group by that column" -->  点击 Run Designer  -> 找到:OptionView ->  将 ShowGroupPanel : 设置为 false ; 2:如何 显示出 GridView 自带的 搜索功能 -->  点击 Run Designer  ->  找到: OptionsFind -> 将AlwaysVisi

DevExpress GridView 列标题点击事件

GridView有RowCellClick事件,即单元格点击事件,但是针对列标题行以及列标题单元格却没有相应的事件. 在这里使用GridView的MouseDown事件.这里同样使用的是GridHitInfo来获取点击位置的信息,来判断是否在列标题上.GridHitInfo根据鼠标点击的x.y坐标获取该点的相关信息,判断是否点击在列标题行内. private void gridView_MouseDown(object sender, MouseEventArgs e) { //鼠标左键点击 i

DevExpress gridview下拉框的再次研究

前几天写了一篇关于研究DevExpress gridview下拉框的随笔(DevExpress gridview下拉框repositoryItemComboBox的使用),被大神(@爱编程的大叔)评论为:成功用世界上最繁琐的方法来使用Devexpress中的Gridview控件中的下拉框,之后就一直在想那肯定是还有更加简便的办法,刚好今天有空闲时间,就去了官网研究起了gridControl的属性(https://documentation.devexpress.com/#WindowsForms

DevExpress gridview下拉框(三)

经过前两次的探索和研究(DevExpress gridview下拉框repositoryItemComboBox的使用 ,DevExpress gridview下拉框的再次研究),今天实习工作上终于用到了,但发现并不能满足我的需求. 当我们绑定了数据源(如:bindingSource1.DataSource = dt)之后,只要我们对gridview单元格数据进行操作,dt也会跟着变.但是我的repositoryItemComboBox绑定了一个Item,Item包含显示值和实际值.Item中的

DevExpress gridView列标题右键菜单管理

1.添加PopupMenuShowing事件 2.PopupMenuShowing事件中的代码如下: private void gridView1_PopupMenuShowing(object sender, DevExpress.XtraGrid.Views.Grid.PopupMenuShowingEventArgs e) { if (e.MenuType == DevExpress.XtraGrid.Views.Grid.GridMenuType.Column)//判断是否是列标题的右键

DevExpress gridview获取单元格坐标

获取坐标(在RowCellClick事件中)的代码如下: private void gridView1_RowCellClick(object sender, DevExpress.XtraGrid.Views.Grid.RowCellClickEventArgs e) { //获取点击单元格左上角的坐标 GridViewInfo info = gridView1.GetViewInfo() as GridViewInfo; GridCellInfo cellInfo = info.GetGri

devexpress gridview

摘要:devexpress gridview Master Detail http://www.devexpress.com/Support/Center/kb/p/K18504.aspx http://www.plurk.com/SophieQ 原文:大专栏  devexpress gridview 原文地址:https://www.cnblogs.com/chinatrump/p/11505511.html

DevExpress.XtraGrid.GridControl 实现自定义tooltip

DevExpress.XtraGrid.GridControl 控件默认的tooltip显示的每一个单元格的文本值,但是实际工作中会出现各种需求.我这里就有一个列是折扣率显示的值是0-1之间的两位小数,比如说0.55想要显示成五五折.那就需要自己来做一下处理了(效果看下图) 首先.在工具栏中找到ToolTipControllerk控件,并且设置GridControl.ToolTipController=MainGvTool              然后再添加的ToolTipController