New to Telerik Reporting? Download free 30-day trial

Custom User Aggregate Functions

User aggregate functions allow you to apply custom logic when accumulating values over a set of rows from the data source. They are used by the Telerik Reporting engine as all built-in aggregate functions.

Implementing a custom aggregate function

User aggregates are public or internal (Public or Friend in VB.NET) classes that implement the IAggregateFunction interface.

Aggregate function implementation accumulates values from each row using the Accumulate method. The aggregate can take an arbitrary number of input parameters and will receive them as items in the object array parameter passed in this method.

The function merges its value with other instances of the aggregate using the Merge method. For example if you implement SUM aggregate and merge an instance of the aggregate with current accumulated value of 4+5=9 within the current aggregate instance with accumulated value of 1+2+3=6 the result should be 15.

The function returns value using the GetValue method.

Apply AggregateFunctionAttribute to the custom aggregate class implementation to define an interface for the users of the aggregate function. The Name parameter of the attribute defines how to refer to the function in expressions.

Example

[AggregateFunction(Description = "Concatenation aggregate. Output: (value1, value2, ...)", Name = "Concatenate")]
class ConcatenateAggregate : IAggregateFunction
{
    string result;

    public void Accumulate(object[] values)
    {
        // The aggregate function expects one parameter
        object value = values[0];

        // null values are not aggregated
        if (null == value)
        {
            return;
        }

        // The actual accumulation
        if (this.result.Length > 0)
        {
            result += ", ";
        }
        this.result += value.ToString();
    }

    public object GetValue()
    {
        return string.Format("({0})", this.result);
    }

    public void Init()
    {
        // Add aggregate function initialization code here if needed
        this.result = string.Empty;
    }

    public void Merge(IAggregateFunction aggregateFunction)
    {
        ConcatenateAggregate aggregate = (ConcatenateAggregate)aggregateFunction;

        if (aggregate.result.Length > 0)
        {
            if (this.result.Length > 0)
            {
                result += ", ";
            }
            this.result += aggregate.result;
        }
    }
}
<AggregateFunction(Description:="Concatenation aggregate. Output: (value1, value2, ...)", Name:="Concatenate")> _
Class ConcatenateAggregate
    Implements IAggregateFunction
    Private result As String

    Public Sub Accumulate(ByVal values As Object()) Implements IAggregateFunction.Accumulate
        ' The aggregate function expects one parameter
        Dim value As Object = values(0)

        ' null values are not aggregated
        If value Is Nothing Then
            Return
        End If

        ' The actual accumulation
        If Me.result.Length > 0 Then
            result += ", "
        End If
        Me.result += value.ToString()
    End Sub

    Public Function GetValue() As Object Implements IAggregateFunction.GetValue
        Return String.Format("({0})", Me.result)
    End Function

    Public Sub Init() Implements IAggregateFunction.Init
        ' Add aggregate function initialization code here if needed
        Me.result = String.Empty
    End Sub

    Public Sub Merge(ByVal aggregateFunction As IAggregateFunction) Implements IAggregateFunction.Merge
        Dim aggregate As ConcatenateAggregate = DirectCast(aggregateFunction, ConcatenateAggregate)

        If aggregate.result.Length > 0 Then
            If Me.result.Length > 0 Then
                result += ", "
            End If
            Me.result += aggregate.result
        End If
    End Sub
End Class

Invoking a Custom Aggregate Function

You can use a custom aggregate within expressions the same way you invoke an built-in aggregate function:

=Concatenate(Fields.ProductName)

Extending Reporting Engine with User Functions

If your custom aggregate functions are linked from an external assembly, in order the Standalone designer to recognize them, you will have to extend the configuration of the start application. To run the report in other project use the same approach - add the assembly to the root folder from where the application is executed and configure it to load the external assembly by extending the configuration.

Custom aggregates are not supported when you preview the report in Visual Studio. To see the aggregate output, use a ReportViewer control.

In this article