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.