This example demonstrates how to implement custom functions for the Expression Editor available in the Web End-User Report Designer.
The project implements the following custom functions:
- CustomFormatFunction that formats a value with the specified format string.
- CountDistinct custom aggregate function that calculates the number of distinct values.
The CustomFormatFunction
class inherits from the ReportCustomFunctionOperatorBase class.
The CountDistinctCustomAggregate
class implements the ICustomAggregateBrowsable interface.
Files to Review
Documentation
- Custom Functions
- Custom Aggregate Functions
- CustomFunctions class
- Add or Remove a Function in the Expression Editor (ASP.NET Core)
More Examples
Does this example address your development requirements/objectives?
(you will be redirected to DevExpress.com to submit your response)
Example Code
C#using DevExpress.XtraReports.Expressions;
using System;
public class CustomFormatFunction : ReportCustomFunctionOperatorBase
{
public override string FunctionCategory
=> "Custom";
public override string Description
=> "CustomFormatFunction(string format, object arg0)" +
"\r\nConverts an arg0 value to a string based on a specified format";
public override bool IsValidOperandCount(int count)
=> count == 2;
public override bool IsValidOperandType(int operandIndex, int operandCount, Type type)
=> true;
public override int MaxOperandCount
=> 2;
public override int MinOperandCount
=> 2;
public override object Evaluate(params object[] operands)
{
string res = String.Format(operands[0].ToString(), operands[1]);
return res;
}
public override string Name
=> "CustomFormatFunction";
public override Type ResultType(params Type[] operands)
{
return typeof(string);
}
}
C#using DevExpress.Data.Filtering;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
public class CountDistinctCustomAggregate : ICustomAggregateFormattable, ICustomAggregateBrowsable {
static readonly CountDistinctCustomAggregate instance = new CountDistinctCustomAggregate();
public static void Register() {
CriteriaOperator.RegisterCustomAggregate(instance);
}
public static void Unregister() {
CriteriaOperator.UnregisterCustomAggregate(instance);
}
public string Name { get { return nameof(CountDistinct); } }
public int MinOperandCount => -1;
public int MaxOperandCount => -1;
public string Description => "This is a custom aggregate function";
Type ICustomAggregate.ResultType(params Type[] operands) {
return typeof(int);
}
object ICustomAggregate.CreateEvaluationContext() {
return new HashSet<object>();
}
bool ICustomAggregate.Process(object context, object[] operands) {
var ctx = (HashSet<object>)context;
ctx.Add(operands[0]);
return false;
}
object ICustomAggregate.GetResult(object context) {
var ctx = (HashSet<object>)context;
return ctx.Count;
}
string ICustomAggregateFormattable.Format(Type providerType, params string[] operands) {
return string.Format("COUNT(distinct {0})", operands[0]);
}
public static object CountDistinct<T>(IEnumerable<T> collection, Expression<Func<T, object>> arg) {
throw new InvalidOperationException("This method should not be called explicitly.");
}
public bool IsValidOperandCount(int count) {
return true;
}
public bool IsValidOperandType(int operandIndex, int operandCount, Type type) {
return true;
}
}
Razor<script type="text/javascript">
function OnBeforeRender(event) {
delete DevExpress.Reporting.Designer.Widgets.reportFunctionDisplay[1].items["LocalDateTimeThisYear"];
}
</script>
@{
var designerRender = Html.DevExpress().ReportDesigner("reportDesigner")
.Height("100%")
.ClientSideEvents(configure => configure.BeforeRender("OnBeforeRender"))
.Bind(Model.ReportDesignerModel);
@designerRender.RenderHtml()
}
@section Scripts {
<link href="~/css/dx-reporting-skeleton-screen.css" rel="stylesheet" />
<link rel="stylesheet" href="~/css/viewer.part.bundle.css" />
<link rel="stylesheet" href="~/css/designer.part.bundle.css" />
<link rel="stylesheet" href="~/css/ace/ace.bundle.css" />
<link rel="stylesheet" href="~/css/dx.material.blue.light.bundle.css" />
<script src="~/js/reporting.thirdparty.bundle.js"></script>
<script src="~/js/viewer.part.bundle.js"></script>
<script src="~/js/designer.part.bundle.js"></script>
@designerRender.RenderScripts()
}