--首發於博客園, 轉載請保留連接 博客原文html
DevExpress Documentation官方地址:GridView.CustomSummaryCalculate Eventexpress
界面上 GridView 顯示的數據裏某些字段在讀出來的時候已經 SUM By FieldA ,在界面上統計時就不能簡單累計總和,條件是 FieldA 相同不能重複相加。this
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 這樣特殊的統計字段只能在代碼實現計算邏輯。事件
以下:
把 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); } }
字段屬性 SummaryItem.SummaryType = Custome,不然 Grid 頁腳沒法顯示
主要 ShowInGroupColumnFooter 是 Step 1 中添加的對應字段, SummaryType 仍爲 Custom
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(); }
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(); }
// 保存 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; } }
(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 或其餘數據源類型顯然是要另外處理的。