How to add a weighted average summary to a DevExpress XtraGrid?

Drew Noakes picture Drew Noakes · Feb 20, 2009 · Viewed 8.7k times · Source

The DevExpress Grid (XtraGrid) allows grids and their groups to have summary calculations. The available options are Count, Max, Min, Avg, Sum, None and Custom.

Has anyone got some sample code that shows how to calculate a weighted average column, based upon the weightings provided as values in another column?

Answer

Drew Noakes picture Drew Noakes · Feb 20, 2009

I ended up working this out, and will post my solution here in case others find it useful.

If a weighted average consists of both a value and a weight per row, then column that contains the value should have the weight GridColumn object assigned to its Tag property. Then, this event handler will do the rest:

private static void gridView_CustomSummaryCalculate(object sender, CustomSummaryEventArgs e)
{
    GridColumn weightColumn = ((GridSummaryItem)e.Item).Tag as GridColumn;

    if (weightColumn == null)
        return;

    switch (e.SummaryProcess)
    {
        case CustomSummaryProcess.Start:
        {
            e.TotalValue = new WeightedAverageCalculator();
            break;
        }
        case CustomSummaryProcess.Calculate:
        {
            double size = Convert.ToDouble(e.FieldValue);
            double weight = Convert.ToDouble(((GridView)sender).GetRowCellValue(e.RowHandle, weightColumn));

            ((WeightedAverageCalculator)e.TotalValue).Add(weight, size);
            break;
        }
        case CustomSummaryProcess.Finalize:
        {
            e.TotalValue = ((WeightedAverageCalculator)e.TotalValue).Value;
            break;
        }
    }
}

private sealed class WeightedAverageCalculator
{
    private double _sumOfProducts;
    private double _totalWeight;

    public void Add(double weight, double size)
    {
        _sumOfProducts += weight * size;
        _totalWeight += weight;
    }

    public double Value
    {
        get { return _totalWeight==0 ? 0 : _sumOfProducts / _totalWeight; }
    }
}

The code assumes that the underlying column values can be converted to doubles via Convert.ToDouble(object).