Example T1013155
Visible to All Users

Reporting for ASP.NET Core - How to Implement a Custom Function in the Expression Editor

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.
    Custom Function in Expression Editor
  • CountDistinct custom aggregate function that calculates the number of distinct values.
    Custom Aggregate Function in Expression Editor

The CustomFormatFunction class inherits from the ReportCustomFunctionOperatorBase class.

The CountDistinctCustomAggregate class implements the ICustomAggregateBrowsable interface.

Files to Review

Documentation

More Examples

Does this example address your development requirements/objectives?

(you will be redirected to DevExpress.com to submit your response)

Example Code

CustomFunctionExample/CustomFunctions/CustomFormatFunction.cs
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); } }
CustomFunctionExample/CustomFunctions/CountDistinctCustomAggregate.cs
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; } }
CustomFunctionExample/Views/Home/Designer.cshtml
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() }

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.