# Custom Summary | WPF Controls | DevExpress Documentation

[Total summaries](/WPF/6128/controls-and-libraries/data-grid/data-summaries/total-summary) and [group summaries](/WPF/6127/controls-and-libraries/data-grid/data-summaries/group-summary) contain predefined aggregate functions. These functions allow you to calculate the following:

- The number of data rows (**Count**).
- The maximum and minimum values (**Max** and **Min**).
- The sum and the average value (**Sum** and **Average**).

Handle the [GridControl.CustomSummary](/WPF/DevExpress.Xpf.Grid.GridControl.CustomSummary) event or use the [GridControl.CustomSummaryCommand](/WPF/DevExpress.Xpf.Grid.GridControl.CustomSummaryCommand) property to apply custom rules to calculate summaries. Custom summaries allow you to:

- Calculate summaries against records that meet specific criteria.
- Involve multiple data fields in calculations.
- Implement complex summary functions (for example, the standard deviation of a population and so on).

If the [GridControl.View](/WPF/DevExpress.Xpf.Grid.GridControl.View) property is set to [TreeListView](/WPF/DevExpress.Xpf.Grid.TreeListView), use the [TreeListView.CustomSummary](/WPF/DevExpress.Xpf.Grid.TreeListView.CustomSummary) event or the [TreeListView.CustomSummaryCommand](/WPF/DevExpress.Xpf.Grid.TreeListView.CustomSummaryCommand) property.

## General Information

To calculate a summary manually:

1. Create a summary item and set its [SummaryItemBase.SummaryType](/WPF/DevExpress.Xpf.Grid.SummaryItemBase.SummaryType) property to [SummaryItemType.Custom](/CoreLibraries/DevExpress.Data.SummaryItemType).
2. Create a command that uses a custom algorithm to calculate summary values.
3. Bind this command to the [GridControl.CustomSummaryCommand](/WPF/DevExpress.Xpf.Grid.GridControl.CustomSummaryCommand) property.

The [GridControl](/WPF/DevExpress.Xpf.Grid.GridControl) calculates its summaries as follows:

- Initialization

    - The GridControl executes the **CustomSummary** command and sets the [SummaryArgs.SummaryProcess](/CoreLibraries/DevExpress.Mvvm.Xpf.SummaryArgs.SummaryProcess) property to **Start**. At this stage, you can initialize summary values (for example, reset internal counters).

- Calculation

    - The GridControl executes the **CustomSummary** command multiple times, once for each data row in a View or group. The [SummaryArgs.SummaryProcess](/CoreLibraries/DevExpress.Mvvm.Xpf.SummaryArgs.SummaryProcess) property is set to **Calculate**. At this stage, you can calculate summaries.

- Finalization

    - The GridControl executes the **CustomSummary** command and sets the [SummaryArgs.SummaryProcess](/CoreLibraries/DevExpress.Mvvm.Xpf.SummaryArgs.SummaryProcess) property to **Finalize**. At this stage, you can assign the calculated summary to the [SummaryArgs.TotalValue](/CoreLibraries/DevExpress.Mvvm.Xpf.SummaryArgs.TotalValue) property.

To skip the **Calculation** stage and calculate a custom summary at the **Initialization** or **Finalization** stage, set the [SummaryArgs.TotalValueReady](/CoreLibraries/DevExpress.Mvvm.Xpf.SummaryArgs.TotalValueReady) property to **true** at the Initialization stage. This skips the **Calculation** stage and starts the **Finalization** stage.

## Calculate Custom Summaries

The following code sample calculates the total number of empty cells in the specified column:

![DevExpress WPF | Grid Control - Custom Summaries](/WPF/images/GridControl_CustomSummaryCommand.png)

[View Example: How to Use Custom Summaries](https://github.com/DevExpress-Examples/wpf-data-grid-summarize-empty-cells)

- MainWindow.xaml

<section id="tabpanel_5vBehDurUZ_tabid-xaml" role="tabpanel" data-tab="tabid-xaml">
<pre><code data-code-links="{&quot;/(CustomSummaryCommand)[^}]/&quot;:&quot;/WPF/DevExpress.Xpf.Grid.GridControl.CustomSummaryCommand&quot;,&quot;RowSummaryArgs&quot;:&quot;/CoreLibraries/DevExpress.Mvvm.Xpf.RowSummaryArgs&quot;,&quot;SummaryType&quot;:&quot;/WPF/DevExpress.Xpf.Grid.SummaryItemBase.SummaryType&quot;,&quot;ViewModelBase&quot;:&quot;/WPF/17351/mvvm-framework/viewmodels/viewmodelbase&quot;}" class="lang-xaml">&lt;dxg:GridControl ItemsSource=&quot;{Binding Items}&quot;
                 CustomSummaryCommand=&quot;{Binding CustomSummaryCommand}&quot;&gt;
    &lt;dxg:GridControl.Columns&gt;
        &lt;dxg:GridColumn FieldName=&quot;Text&quot; GroupIndex=&quot;0&quot; /&gt;
        &lt;dxg:GridColumn FieldName=&quot;Number&quot; /&gt;
    &lt;/dxg:GridControl.Columns&gt;
    &lt;dxg:GridControl.View&gt;
        &lt;dxg:TableView AutoWidth=&quot;True&quot;
                       NavigationStyle=&quot;Cell&quot;
                       TotalSummaryPosition=&quot;Bottom&quot; /&gt;
    &lt;/dxg:GridControl.View&gt;
    &lt;dxg:GridControl.TotalSummary&gt;
        &lt;dxg:GridSummaryItem DisplayFormat=&quot;Total empty cells count: {0}&quot;
                             FieldName=&quot;Number&quot;
                             SummaryType=&quot;Custom&quot; /&gt;
    &lt;/dxg:GridControl.TotalSummary&gt;
    &lt;dxg:GridControl.GroupSummary&gt;
        &lt;dxg:GridSummaryItem DisplayFormat=&quot;Group empty cells count: {0}&quot;
                             FieldName=&quot;Number&quot;
                             SummaryType=&quot;Custom&quot; /&gt;
    &lt;/dxg:GridControl.GroupSummary&gt;
&lt;/dxg:GridControl&gt;
</code></pre></section>

- MainViewModel.cs
- MainViewModel.vb

<section id="tabpanel_5vBehDurUZ-1_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;/(CustomSummaryCommand)[^}]/&quot;:&quot;/WPF/DevExpress.Xpf.Grid.GridControl.CustomSummaryCommand&quot;,&quot;RowSummaryArgs&quot;:&quot;/CoreLibraries/DevExpress.Mvvm.Xpf.RowSummaryArgs&quot;,&quot;SummaryType&quot;:&quot;/WPF/DevExpress.Xpf.Grid.SummaryItemBase.SummaryType&quot;,&quot;ViewModelBase&quot;:&quot;/WPF/17351/mvvm-framework/viewmodels/viewmodelbase&quot;,&quot;/ (DevExpress.Mvvm)(?:;|$)/&quot;:&quot;/CoreLibraries/DevExpress.Mvvm&quot;,&quot;/ (DevExpress.Mvvm.DataAnnotations)(?:;|$)/&quot;:&quot;/CoreLibraries/DevExpress.Mvvm.DataAnnotations&quot;,&quot;/ (DevExpress.Mvvm.Xpf)(?:;|$)/&quot;:&quot;/CoreLibraries/DevExpress.Mvvm.Xpf&quot;}" class="lang-csharp">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 != &quot;Number&quot;)
            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;
    }
}
</code></pre></section>
<section id="tabpanel_5vBehDurUZ-1_tabid-vb" role="tabpanel" data-tab="tabid-vb" aria-hidden="true" hidden="hidden">
<pre><code data-code-links="{&quot;/(CustomSummaryCommand)[^}]/&quot;:&quot;/WPF/DevExpress.Xpf.Grid.GridControl.CustomSummaryCommand&quot;,&quot;RowSummaryArgs&quot;:&quot;/CoreLibraries/DevExpress.Mvvm.Xpf.RowSummaryArgs&quot;,&quot;SummaryType&quot;:&quot;/WPF/DevExpress.Xpf.Grid.SummaryItemBase.SummaryType&quot;,&quot;ViewModelBase&quot;:&quot;/WPF/17351/mvvm-framework/viewmodels/viewmodelbase&quot;,&quot;/ (DevExpress.Mvvm)(?:;|$)/&quot;:&quot;/CoreLibraries/DevExpress.Mvvm&quot;,&quot;/ (DevExpress.Mvvm.DataAnnotations)(?:;|$)/&quot;:&quot;/CoreLibraries/DevExpress.Mvvm.DataAnnotations&quot;,&quot;/ (DevExpress.Mvvm.Xpf)(?:;|$)/&quot;:&quot;/CoreLibraries/DevExpress.Mvvm.Xpf&quot;}" class="lang-vb">Imports DevExpress.Mvvm
Imports DevExpress.Mvvm.DataAnnotations
Imports DevExpress.Mvvm.Xpf
&#39; ...
Public Class MainViewModel
    Inherits ViewModelBase
&#39; ...
    &lt;Command&gt;
    Public Sub CustomSummary(ByVal args As RowSummaryArgs)
        If Not Equals(args.SummaryItem.PropertyName, &quot;Number&quot;) 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
</code></pre></section>

## Calculate Custom Summaries Based on Predefined Summaries

The [GridControl](/WPF/DevExpress.Xpf.Grid.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:

1. Create a custom summary.
2. Handle the [GridControl.CustomSummary](/WPF/DevExpress.Xpf.Grid.GridControl.CustomSummary) / [TreeListView.CustomSummary](/WPF/DevExpress.Xpf.Grid.TreeListView.CustomSummary) event.
3. At the **Initialization** stage, set the [e.TotalValueReady](/CoreLibraries/DevExpress.Data.CustomSummaryEventArgs.TotalValueReady) property to `true` to skip the **Calculation** stage.
4. Use the [DataControlBase.GetTotalSummaryValue](/WPF/DevExpress.Xpf.Grid.DataControlBase.GetTotalSummaryValue%28DevExpress.Xpf.Grid.SummaryItemBase%29) method to obtain predefined summaries at the **Finalization** stage.

![Calculate Custom Summaries Based on Predefined Summaries](/WPF/images/WPF_Grid_CustomSummaries_PredefinedSummaries.png)

- XAML

<section id="tabpanel_wQTiBzCLGg_tabid-xaml" role="tabpanel" data-tab="tabid-xaml">
<pre><code data-code-links="{&quot;ViewModelBase&quot;:&quot;/WPF/17351/mvvm-framework/viewmodels/viewmodelbase&quot;,&quot;RowSummaryExistsArgs&quot;:&quot;/CoreLibraries/DevExpress.Mvvm.Xpf.RowSummaryExistsArgs&quot;,&quot;GroupSummary&quot;:&quot;/WPF/DevExpress.Xpf.Grid.GridControl.GroupSummary&quot;}" class="lang-xaml">&lt;dxg:GridControl ...
                 CustomSummary=&quot;grid_CustomSummary&quot;&gt;
    &lt;dxg:GridColumn FieldName=&quot;ProductName&quot;/&gt;
    &lt;dxg:GridColumn FieldName=&quot;UnitPrice&quot;/&gt;
    &lt;dxg:GridColumn FieldName=&quot;Quantity&quot;/&gt;
    &lt;dxg:GridControl.TotalSummary&gt;
        &lt;dxg:GridSummaryItem x:Name=&quot;avgPrice&quot; FieldName=&quot;UnitPrice&quot; SummaryType=&quot;Average&quot;/&gt;
        &lt;dxg:GridSummaryItem x:Name=&quot;avgQuantity&quot; FieldName=&quot;Quantity&quot; SummaryType=&quot;Average&quot;/&gt;
        &lt;dxg:GridSummaryItem ShowInColumn=&quot;ProductName&quot; SummaryType=&quot;Custom&quot; 
                             DisplayFormat=&quot;{}Average order: {0:c}&quot;/&gt;
    &lt;/dxg:GridControl.TotalSummary&gt;
    &lt;dxg:GridControl.View&gt;
        &lt;dxg:TableView ...
                       TotalSummaryPosition=&quot;Bottom&quot;&gt;
        &lt;/dxg:TableView&gt;
    &lt;/dxg:GridControl.View&gt;
&lt;/dxg:GridControl&gt;
</code></pre></section>

- C#
- VB.NET

<section id="tabpanel_wQTiBzCLGg-1_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;ViewModelBase&quot;:&quot;/WPF/17351/mvvm-framework/viewmodels/viewmodelbase&quot;,&quot;RowSummaryExistsArgs&quot;:&quot;/CoreLibraries/DevExpress.Mvvm.Xpf.RowSummaryExistsArgs&quot;,&quot;GroupSummary&quot;:&quot;/WPF/DevExpress.Xpf.Grid.GridControl.GroupSummary&quot;}" class="lang-csharp">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;
        }
    }
}
</code></pre></section>
<section id="tabpanel_wQTiBzCLGg-1_tabid-vb" role="tabpanel" data-tab="tabid-vb" aria-hidden="true" hidden="hidden">
<pre><code data-code-links="{&quot;ViewModelBase&quot;:&quot;/WPF/17351/mvvm-framework/viewmodels/viewmodelbase&quot;,&quot;RowSummaryExistsArgs&quot;:&quot;/CoreLibraries/DevExpress.Mvvm.Xpf.RowSummaryExistsArgs&quot;,&quot;GroupSummary&quot;:&quot;/WPF/DevExpress.Xpf.Grid.GridControl.GroupSummary&quot;}" class="lang-vb">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
</code></pre></section>

You can use the [e.GetGroupSummary](/CoreLibraries/DevExpress.Data.CustomSummaryEventArgs.GetGroupSummary%28System.Int32-System.Object%29) method to obtain predefined group summary values.

## Specify Whether to Calculate Summaries

The [CustomSummaryExists](/WPF/DevExpress.Xpf.Grid.GridControl.CustomSummaryExists) event or the [CustomSummaryExistsCommand](/WPF/DevExpress.Xpf.Grid.GridControl.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:

![DevExpress WPF | Grid Control - Custom Summary Exists](/WPF/images/GridControl_CustomSummaryExistsCommand.png)

[View Example: How to Display Group Summaries](https://github.com/DevExpress-Examples/wpf-data-grid-display-group-summaries)

- MainWindow.xaml

<section id="tabpanel_wQTiBzCLGg-2_tabid-xaml" role="tabpanel" data-tab="tabid-xaml">
<pre><code data-code-links="{&quot;ViewModelBase&quot;:&quot;/WPF/17351/mvvm-framework/viewmodels/viewmodelbase&quot;,&quot;RowSummaryExistsArgs&quot;:&quot;/CoreLibraries/DevExpress.Mvvm.Xpf.RowSummaryExistsArgs&quot;,&quot;GroupSummary&quot;:&quot;/WPF/DevExpress.Xpf.Grid.GridControl.GroupSummary&quot;}" class="lang-xaml">&lt;dxg:GridControl x:Name=&quot;grid&quot;
                 ItemsSource=&quot;{Binding AccountList}&quot;
                 CustomSummaryExistsCommand=&quot;{Binding CustomSummaryExistsCommand}&quot;&gt;
                 &lt;!-- ... --&gt;
    &lt;dxg:GridControl.GroupSummary&gt;
        &lt;dxg:GridSummaryItem FieldName=&quot;Age&quot; SummaryType=&quot;Min&quot;/&gt;
        &lt;dxg:GridSummaryItem FieldName=&quot;Age&quot; SummaryType=&quot;Max&quot;/&gt;
    &lt;/dxg:GridControl.GroupSummary&gt;
&lt;/dxg:GridControl&gt;
</code></pre></section>

- MainViewModel.cs
- MainViewModel.vb

<section id="tabpanel_wQTiBzCLGg-3_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;ViewModelBase&quot;:&quot;/WPF/17351/mvvm-framework/viewmodels/viewmodelbase&quot;,&quot;RowSummaryExistsArgs&quot;:&quot;/CoreLibraries/DevExpress.Mvvm.Xpf.RowSummaryExistsArgs&quot;,&quot;GroupSummary&quot;:&quot;/WPF/DevExpress.Xpf.Grid.GridControl.GroupSummary&quot;,&quot;/ (DevExpress.Mvvm)(?:;|$)/&quot;:&quot;/CoreLibraries/DevExpress.Mvvm&quot;,&quot;/ (DevExpress.Mvvm.DataAnnotations)(?:;|$)/&quot;:&quot;/CoreLibraries/DevExpress.Mvvm.DataAnnotations&quot;,&quot;/ (DevExpress.Mvvm.Xpf)(?:;|$)/&quot;:&quot;/CoreLibraries/DevExpress.Mvvm.Xpf&quot;}" class="lang-csharp">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;
    }
}
</code></pre></section>
<section id="tabpanel_wQTiBzCLGg-3_tabid-vb" role="tabpanel" data-tab="tabid-vb" aria-hidden="true" hidden="hidden">
<pre><code data-code-links="{&quot;ViewModelBase&quot;:&quot;/WPF/17351/mvvm-framework/viewmodels/viewmodelbase&quot;,&quot;RowSummaryExistsArgs&quot;:&quot;/CoreLibraries/DevExpress.Mvvm.Xpf.RowSummaryExistsArgs&quot;,&quot;GroupSummary&quot;:&quot;/WPF/DevExpress.Xpf.Grid.GridControl.GroupSummary&quot;,&quot;/ (DevExpress.Mvvm)(?:;|$)/&quot;:&quot;/CoreLibraries/DevExpress.Mvvm&quot;,&quot;/ (DevExpress.Mvvm.DataAnnotations)(?:;|$)/&quot;:&quot;/CoreLibraries/DevExpress.Mvvm.DataAnnotations&quot;,&quot;/ (DevExpress.Mvvm.Xpf)(?:;|$)/&quot;:&quot;/CoreLibraries/DevExpress.Mvvm.Xpf&quot;}" class="lang-vb">Imports DevExpress.Mvvm
Imports DevExpress.Mvvm.DataAnnotations
Imports DevExpress.Mvvm.Xpf
&#39; ...
Public Class MainViewModel
    Inherits ViewModelBase
&#39; ...
    &lt;Command&gt;
    Public Sub CustomSummaryExistsCommand(ByVal args As RowSummaryExistsArgs)
        args.Exists = args.GroupPath(0).GroupLevel = 0
    End Sub
End Class
</code></pre></section>