wpf-6129-controls-and-libraries-data-grid-data-summaries-custom-summary.md
Total summaries and group summaries contain predefined aggregate functions. These functions allow you to calculate the following:
Handle the GridControl.CustomSummary event or use the GridControl.CustomSummaryCommand property to apply custom rules to calculate summaries. Custom summaries allow you to:
If the GridControl.View property is set to TreeListView, use the TreeListView.CustomSummary event or the TreeListView.CustomSummaryCommand property.
To calculate a summary manually:
The GridControl calculates its summaries as follows:
InitializationThe GridControl executes the CustomSummary command and sets the SummaryArgs.SummaryProcess property to Start. At this stage, you can initialize summary values (for example, reset internal counters).CalculationThe GridControl executes the CustomSummary command multiple times, once for each data row in a View or group. The SummaryArgs.SummaryProcess property is set to Calculate. At this stage, you can calculate summaries.FinalizationThe GridControl executes the CustomSummary command and sets the SummaryArgs.SummaryProcess property to Finalize. At this stage, you can assign the calculated summary to the SummaryArgs.TotalValue property.
To skip the Calculation stage and calculate a custom summary at the Initialization or Finalization stage, set the SummaryArgs.TotalValueReady property to true at the Initialization stage. This skips the Calculation stage and starts the Finalization stage.
The following code sample calculates the total number of empty cells in the specified column:
View Example: How to Use Custom Summaries
<dxg:GridControl ItemsSource="{Binding Items}"
CustomSummaryCommand="{Binding CustomSummaryCommand}">
<dxg:GridControl.Columns>
<dxg:GridColumn FieldName="Text" GroupIndex="0" />
<dxg:GridColumn FieldName="Number" />
</dxg:GridControl.Columns>
<dxg:GridControl.View>
<dxg:TableView AutoWidth="True"
NavigationStyle="Cell"
TotalSummaryPosition="Bottom" />
</dxg:GridControl.View>
<dxg:GridControl.TotalSummary>
<dxg:GridSummaryItem DisplayFormat="Total empty cells count: {0}"
FieldName="Number"
SummaryType="Custom" />
</dxg:GridControl.TotalSummary>
<dxg:GridControl.GroupSummary>
<dxg:GridSummaryItem DisplayFormat="Group empty cells count: {0}"
FieldName="Number"
SummaryType="Custom" />
</dxg:GridControl.GroupSummary>
</dxg:GridControl>
using DevExpress.Mvvm;
using DevExpress.Mvvm.DataAnnotations;
using DevExpress.Mvvm.Xpf;
// ...
public class MainViewModel : ViewModelBase {
// ...
[Command]
public void CustomSummary(RowSummaryArgs args) {
if(args.SummaryItem.PropertyName != "Number")
return;
if(args.SummaryProcess == SummaryProcess.Start) {
args.TotalValue = 0;
}
if(args.SummaryProcess == SummaryProcess.Calculate) {
if(IsEmptyCell(args.FieldValue))
args.TotalValue = (int)args.TotalValue + 1;
}
}
bool IsEmptyCell(object fieldValue) {
return !((int?)fieldValue).HasValue;
}
}
Imports DevExpress.Mvvm
Imports DevExpress.Mvvm.DataAnnotations
Imports DevExpress.Mvvm.Xpf
' ...
Public Class MainViewModel
Inherits ViewModelBase
' ...
<Command>
Public Sub CustomSummary(ByVal args As RowSummaryArgs)
If Not Equals(args.SummaryItem.PropertyName, "Number") Then Return
If args.SummaryProcess = SummaryProcess.Start Then
args.TotalValue = 0
End If
If args.SummaryProcess = SummaryProcess.Calculate Then
If IsEmptyCell(args.FieldValue) Then args.TotalValue = CInt(args.TotalValue) + 1
End If
End Sub
Private Function IsEmptyCell(ByVal fieldValue As Object) As Boolean
Return Not CType(fieldValue, Integer?).HasValue
End Function
End Class
The GridControl calculates custom summaries after predefined summaries ( Count , Sum , Min , and so on). As a result, you can use predefined summary values to calculate custom summaries:
true to skip the Calculation stage.<dxg:GridControl ...
CustomSummary="grid_CustomSummary">
<dxg:GridColumn FieldName="ProductName"/>
<dxg:GridColumn FieldName="UnitPrice"/>
<dxg:GridColumn FieldName="Quantity"/>
<dxg:GridControl.TotalSummary>
<dxg:GridSummaryItem x:Name="avgPrice" FieldName="UnitPrice" SummaryType="Average"/>
<dxg:GridSummaryItem x:Name="avgQuantity" FieldName="Quantity" SummaryType="Average"/>
<dxg:GridSummaryItem ShowInColumn="ProductName" SummaryType="Custom"
DisplayFormat="{}Average order: {0:c}"/>
</dxg:GridControl.TotalSummary>
<dxg:GridControl.View>
<dxg:TableView ...
TotalSummaryPosition="Bottom">
</dxg:TableView>
</dxg:GridControl.View>
</dxg:GridControl>
private void grid_CustomSummary(object sender, DevExpress.Data.CustomSummaryEventArgs e) {
if (e.IsTotalSummary) {
switch (e.SummaryProcess) {
case DevExpress.Data.CustomSummaryProcess.Start:
e.TotalValueReady = true;
break;
case DevExpress.Data.CustomSummaryProcess.Finalize:
var averagePrice = (decimal)grid.GetTotalSummaryValue(avgPrice);
var averageQuantity = (decimal)grid.GetTotalSummaryValue(avgQuantity);
e.TotalValue = averagePrice * averageQuantity;
break;
}
}
}
Private Sub grid_CustomSummary(ByVal sender As Object, ByVal e As DevExpress.Data.CustomSummaryEventArgs)
If e.IsTotalSummary Then
Select Case e.SummaryProcess
Case DevExpress.Data.CustomSummaryProcess.Start
e.TotalValueReady = True
Case DevExpress.Data.CustomSummaryProcess.Finalize
Dim averagePrice = CDec(grid.GetTotalSummaryValue(avgPrice))
Dim averageQuantity = CDec(grid.GetTotalSummaryValue(avgQuantity))
e.TotalValue = averagePrice * averageQuantity
End Select
End If
End Sub
You can use the e.GetGroupSummary method to obtain predefined group summary values.
The CustomSummaryExists event or the CustomSummaryExistsCommand property allows you to specify which summaries should be calculated and displayed.
The following example calculates group summaries only for the top group level:
View Example: How to Display Group Summaries
<dxg:GridControl x:Name="grid"
ItemsSource="{Binding AccountList}"
CustomSummaryExistsCommand="{Binding CustomSummaryExistsCommand}">
<!-- ... -->
<dxg:GridControl.GroupSummary>
<dxg:GridSummaryItem FieldName="Age" SummaryType="Min"/>
<dxg:GridSummaryItem FieldName="Age" SummaryType="Max"/>
</dxg:GridControl.GroupSummary>
</dxg:GridControl>
using DevExpress.Mvvm;
using DevExpress.Mvvm.DataAnnotations;
using DevExpress.Mvvm.Xpf;
// ...
public class MainViewModel : ViewModelBase {
// ...
[Command]
public void CustomSummaryExistsCommand(RowSummaryExistsArgs args) {
args.Exists = args.GroupPath[0].GroupLevel == 0;
}
}
Imports DevExpress.Mvvm
Imports DevExpress.Mvvm.DataAnnotations
Imports DevExpress.Mvvm.Xpf
' ...
Public Class MainViewModel
Inherits ViewModelBase
' ...
<Command>
Public Sub CustomSummaryExistsCommand(ByVal args As RowSummaryExistsArgs)
args.Exists = args.GroupPath(0).GroupLevel = 0
End Sub
End Class