views:

2181

answers:

3

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?

A: 

If you provide your own lambda expression inside the sum you should be able to group them by a standard sum. I think this should work:

var grouped = from item in items orderby item.Group group item by item.Group into grp select new { Average= grp.Sum(row => row.Value * row.Weight) };

-MBirchmeier

MBirchmeier
@MBirchmeier, thanks for the answer but this won't integrate with the grid control's API.
Drew Noakes
Sorry this early in the morning I was thinking LINQ could be used as a datasource without bothering to check that. I would imagine you need to use the 'custom' function, but I can't find any documentation on it offhand.
MBirchmeier
+1  A: 

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).

Drew Noakes
A: 

Drew, if I am using a XtraPivotGrid? I dont have CustomSummaryCalculate event, GridSummaryItem property, etc... Thanks.

Sorry Sebagiar, I haven't used that control. Good luck.
Drew Noakes