New to Telerik UI for WinForms? Download free 30-day trial

Custom Aggregation

RadPivotGrid is designed to aggregate data and it provides an API for assigning special aggregation functions performing custom calculations. For the purpose of this example we will use a LocalDataSourceProvider object and we will bind the pivot control to the Orders table from the Northwind database as explained here.

Figure 1: Using the Built-in Sum function

WinForms RadPivotGrid Using the Built-in *Sum* function

Figure 2: Using the Custom Sqrt Of Sum function

WinForms RadPivotGrid Using the Custom *Sqrt Of Sum* function

Defining a Custom Aggregation Function

Our new function will be almost the same as the already available AggregateFunctions.Sum, with the important difference that it will calculate not the sum of the items, but the sum of their square roots.

Custom Function Logic

public class SqrtSumAggregateFunction : Telerik.Pivot.Core.Aggregates.AggregateFunction
{
    public override string DisplayName
    {
        get { return "Sqrt Of Sum"; }
    }
    protected override AggregateValue CreateAggregate(Type dataType)
    {
        return new SqrtSumAggregate();
    }
    public override string GetStringFormat(Type dataType, string format)
    {
        if (format == null)
        {
            return "G";
        }
        return format;
    }
    public override string ToString()
    {
        return "Sqrt Of Sum";
    }
    public override bool Equals(object obj)
    {
        return obj is SqrtSumAggregateFunction;
    }
    protected override void CloneCore(Telerik.Pivot.Core.Cloneable source)
    {
    }
    protected override Telerik.Pivot.Core.Cloneable CreateInstanceCore()
    {
        return new SqrtSumAggregateFunction();
    }
    protected override AggregateValue CreateAggregate(IAggregateContext context)
    {
        return this.CreateAggregate(context.DataType);
    }
}

Defining a Custom Aggregate Value

We also need to create a custom aggregate value class which will be used by our newly defined function to perform the actual calculation.

Custom Aggregate Logic

public sealed class SqrtSumAggregate : AggregateValue, IConvertibleAggregateValue<double>
{
    private double sum;
    private bool hasError = false;
    protected override object GetValueOverride()
    {
        return Math.Round(Math.Sqrt(this.sum), 2);
    }
    protected override void AccumulateOverride(object value)
    {
        this.sum += Convert.ToDouble(value, CultureInfo.InvariantCulture);
    }
    protected override void MergeOverride(AggregateValue childAggregate)
    {
        var sumAggregate = childAggregate as SqrtSumAggregate;
        if (sumAggregate != null)
        {
            this.sum += sumAggregate.sum;
        }
        else
        {
            double doubleValue;
            if (AggregateValueExtensions.TryConvertValue<double>(childAggregate, out doubleValue))
            {
                this.sum += doubleValue;
            }
            else
            {
                this.sum = 0;
                this.hasError = true;
            }
        }
    }
    bool IConvertibleAggregateValue<double>.TryConvertValue(out double value)
    {
        if (this.hasError)
        {
            value = 0;
            return false;
        }
        value = (double)this.sum;
        return true;
    }
}

Assigning the Custom Function

We can make use of our new function by assigning it to the AggregateFunction property of a PropertyAggregateDescription object before setting it to our pivot.

The Custom Dialogs article demonstrates how the custom function can be added to the Aggregate Options Dialog.

Using the Custom Aggregate Function

LocalDataSourceProvider dataProvider = new LocalDataSourceProvider();
dataProvider.ItemsSource = dataset.Orders;
dataProvider.AggregateDescriptions.Add(new PropertyAggregateDescription() { PropertyName = "Freight", AggregateFunction = new SqrtSumAggregateFunction() });
this.radPivotGrid1.DataProvider = dataProvider;

If you add calculated fields in code behind, you have to set the ItemsSource of LocalDataSourceProvider after you have added all calculated fields or to wrap the code between (including setting the ItemsSource ) BeginInit/EndInit methods (or inside using DeferRefresh() { ... } section ).

Figure 2: Calculated Field in RadPivotGrid

WinForms RadPivotGrid Calculated Field in RadPivotGrid