xtrareports-403888-feature-guide-to-devexpress-reports-use-expressions-custom-functions.md
If you build an Expression, you can use functions. DevExpress Reports ship with a number of predefined functions that address common user scenarios. You can also implement and register custom functions. This topic explain how you can do that. In essence, you need to create a class the implements certain interfaces. The scope of your custom function then depends on the interfaces you implemented, on the attributes you applied to the class, and on the registration method you chose.
For information on custom aggregate functions, review the following help topic: Custom Aggregate Functions.
To create a custom function, define a class that implements one or more of the following interfaces:
ICustomFunctionOperatorDeclares the base functionality for custom functions.ICustomFunctionOperatorBrowsableContains descriptive information about a custom function for use in the Expression editor (category, description, number of parameters).ICustomFunctionOperatorFormattableAllows you to use the Query Builder or filter editor to insert a string into SQL queries generated for SELECT operations.ICustomFunctionDisplayAttributesAllows you to create a custom function displayed as a comparison operator and specify the operator’s display settings.
You should register custom functions in your Reporting application. When you register a function, you can choose between two scopes in which the function is available:
Query Builder
Data Wizard
Place an attribute on a custom function to enable it in the Visual Studio Report Designer. Use the following attribute:
VSDesignerCustomFunctionAttributeRegisters a custom function in the Visual Studio Report Designer. You can specify the VSDesignerCustomFunctionScope attribute argument to define the registration scope in the Visual Studio Report Designer.
using DevExpress.XtraReports.Design;
using DevExpress.XtraReports.Expressions;
// ...
[VSDesignerCustomFunction]
public class MakeDate : ReportCustomFunctionOperatorBase {
// ...
}
// ...
[VSDesignerCustomFunction(VSDesignerCustomFunctionScope.Reports)]
public class ReportCustomFunctionOperator : ReportCustomFunctionOperatorBase {
// ...
}
// ...
[VSDesignerCustomFunction]
public class CustomFunctionInQuery : ICustomFunctionOperatorFormattable, ICustomFunctionOperatorBrowsable {
// ...
}
Imports DevExpress.XtraReports.Design
Imports DevExpress.XtraReports.Expressions
' ...
<VSDesignerCustomFunction>
Public Class MakeDate
Inherits ReportCustomFunctionOperatorBase
' ...
End Class
' ...
<VSDesignerCustomFunction(VSDesignerCustomFunctionScope.Reports)>
Public Class ReportCustomFunctionOperator
Inherits ReportCustomFunctionOperatorBase
' ...
End Class
' ...
<VSDesignerCustomFunction>
Public Class CustomFunctionInQuery
Implements ICustomFunctionOperatorFormattable, ICustomFunctionOperatorBrowsable
' ...
End Class
At runtime use one of the following methods:
CriteriaOperator.RegisterCustomFunctionRegisters the function so that it can be accessed anywhere in the application. The available scopes are Data Access and Reporting.CustomFunctions.Register Registers a function so that it is only available in the Reporting scope.
using DevExpress.Data.Filtering;
using DevExpress.XtraReports.Expressions;
// ...
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
CriteriaOperator.RegisterCustomFunction(new CustomFunctionInQuery());
CustomFunctions.Register(new MakeDate());
}
// ...
}
Imports DevExpress.Data.Filtering
Imports DevExpress.XtraReports.Expressions
' ...
Partial Public Class Form1
Public Sub New()
InitializeComponent()
CriteriaOperator.RegisterCustomFunction(New CustomFunctionInQuery())
CustomFunctions.Register(New MakeDate())
End Sub
' ...
End Class
To add a custom function, create a ReportCustomFunctionOperatorBase class descendant.
The following code defines the MakeDate(int year, int month, int day) custom function in the new Date & Time category:
using DevExpress.Data.Filtering;
using DevExpress.Xpo.DB;
using DevExpress.XtraReports.Design;
using DevExpress.XtraReports.Expressions;
using System;
using System.Linq;
// ...
[VSDesignerCustomFunction]
public class MakeDate : ReportCustomFunctionOperatorBase {
public override string FunctionCategory => "Date & Time";
public override int MinOperandCount => 3;
public override int MaxOperandCount => 3;
public override object Evaluate(params object[] operands) {
var ints = operands.Cast<int>().ToArray();
return new DateTime(ints[0], ints[1], ints[2]);
}
public override bool IsValidOperandType(int operandIndex, int operandCount, Type type) {
if (operandIndex >= operandCount)
return false;
return type == typeof(int);
}
public override string Description => "MakeDate(int year, int month, int day)\r\nCreates Datetime instance based on passed year, month, day values";
public override string Name => "MakeDate";
}
Imports Microsoft.VisualBasic
Imports DevExpress.Data.Filtering
Imports DevExpress.Xpo.DB
Imports DevExpress.XtraReports.Design
Imports DevExpress.XtraReports.Expressions
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Threading.Tasks
' ...
<VSDesignerCustomFunction>
Public Class MakeDate
Inherits ReportCustomFunctionOperatorBase
Public Overrides ReadOnly Property FunctionCategory() As String
Get
Return "Date & Time"
End Get
End Property
Public Overrides ReadOnly Property MinOperandCount() As Integer
Get
Return 3
End Get
End Property
Public Overrides ReadOnly Property MaxOperandCount() As Integer
Get
Return 3
End Get
End Property
Public Overrides Function Evaluate(ParamArray ByVal operands() As Object) As Object
Dim ints = operands.Cast(Of Integer)().ToArray()
Return New Date(ints(0), ints(1), ints(2))
End Function
Public Overrides Function IsValidOperandType(ByVal operandIndex As Integer, ByVal operandCount As Integer, ByVal type As Type) As Boolean
If operandIndex >= operandCount Then
Return False
End If
Return type Is GetType(Integer)
End Function
Public Overrides ReadOnly Property Description() As String
Get
Return "MakeDate(int year, int month, int day)" & ControlChars.CrLf & "Creates Datetime instance based on passed year, month, day values"
End Get
End Property
Public Overrides ReadOnly Property Name() As String
Get
Return "MakeDate"
End Get
End Property
End Class
The VSDesignerCustomFunction attribute without arguments enables the function globally in Visual Studio Report Designer, that is, the function is available in the Data Access and Reporting scopes.
Call the CustomFunctions.Register static method at application startup:
using DevExpress.XtraReports.Expressions;
// ...
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
// ...
CustomFunctions.Register(new MakeDate());
}
// ...
}
Imports DevExpress.XtraReports.Expressions
' ...
Partial Public Class Form1
Public Sub New()
InitializeComponent()
' ...
CustomFunctions.Register(New MakeDate())
End Sub
' ...
End Class
After registration, the function is available in the Expression Editor and expression bindings at runtime.
To unregister a previously registered function, call the CustomFunctions.Unregister static method.
Unregistered functions are not available in the Expression Editor. An expression that has unregistered functions is evaluated as an empty value.
The Expression Editor displays the MakeDate function in the Date & Time category:
If you develop a web application, review the following help topics for more information: