Web Report Designer — Custom Controls and Expressions Registration (v23.1)

Reporting Team Blog
29 December 2023

Custom Control Integration

As you may already know, we've made custom report control registration within DevExpress Reports much easier. To address the needs of web developers, v23.1+ includes streamlined custom control registration support (implemented at the server level). If your solution requires the use of custom report controls, all you'll need to do is add controls to a custom controls collection in the server-side report design model. JavaScript functions, properties, and values will be generated automatically.

Label with Rounded Corners — a Custom Control for Multiple Platforms

Let's create a sample application (for all supported web platforms) to help illustrate the flexibility of our custom report control registration process. 

The following GitHub examples demonstrate creation/use of custom report controls:

The first example is versatile: explore our implementation to learn how to create custom report controls with rounded corners — XRRoundLabel and XRRoundPanel, and the Swiss QR Bill control. Follow the steps below to register the XRRoundLabel control in a web application.

  1. Download the project from GitHub.
  2. Open the Blazor sample solution and add the DevExpress.XtraReports.CustomControls.RoundedControls project to the solution. Reference the project in the Blazor sample project.
  3. Rebuild the solution.
  4. Add the XRRoundControl type to the Report Designer collection of custom controls:

@page "/reportdesigner"
<DxReportDesigner ReportName="TestReport" Height="calc(100vh - 130px)" 
                  Width="100%" AllowMDI="true"
    <DxReportDesignerWizardSettings UseFullscreenWizard="true" />
@code {
    List<Type> customTypes = new List<Type> { 
        typeof(DevExpress.XtraReports.CustomControls.RoundBordersControls.XRRoundLabel) };

Finally, launch the application. You will see that the custom control appears in the toolbar (with the default question mark icon):

Icon, Tooltip, and Toolbar Position — Client-Side Configuration

To change the default icon, add an svg template with a name that matches the fully qualified type name of the custom control:

  <script type="text/html" id="dxrd-svg-toolbox-devexpress_xtrareports_customcontrols_roundborderscontrols_xrroundlabel">
      <svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
        <g clip-path="url(#a)">
          <path d="M22.7 28H27L18.3 4h-4.7L5 28h4.3l2.2-6h9.1l2.1 6Zm-9.8-10L16 9.4l3.1 8.6h-6.2Z" fill="#1177D7"/>
          <rect x="1" y="1" width="30" height="30" rx="5" stroke="#727272" stroke-width="2"/>
          <clipPath id="a">
            <path fill="#fff" d="M0 0h32v32H0z"/>

To change the tooltip and specify the location in the toolbar, handle the client-side CustomizeToolbox event as follows:

@page "/reportdesigner"

<DxReportDesigner ReportName="TestReport" Height="calc(100vh - 130px)" 
                  Width="100%" AllowMDI="true"
    <DxReportDesignerWizardSettings UseFullscreenWizard="true" />
    <DxReportDesignerCallbacks CustomizeToolbox="onCustomizeToolbox" />

@code {
    List<Type> customTypes = new List<Type> { 
        typeof(DevExpress.XtraReports.CustomControls.RoundBordersControls.XRRoundLabel) };

function onCustomizeToolbox(s,e){
    var info = e.ControlsFactory.getControlInfo("DevExpress.XtraReports.CustomControls.RoundBordersControls.XRRoundLabel");
    var labelInfo = e.ControlsFactory.getControlInfo("XRLabel");
    info.displayName = "Rounded Label";
    info.toolboxIndex = labelInfo.toolboxIndex - 1;
    info.group = labelInfo.group;            

Start the application to review changes:

If you drag a control from the toolbar onto the designer surface, the control is rendered as expected (with rounded corners):

While our modification appears on screen, after switching to Print Preview mode we see that the control is not printed as a label with rounded corners (it's printed as a simple label). First, this happens because the report document is generated on the server (rendered to the RoundLabelBrick class rather than to one of the brick classes known to the document generation engine). The RoundLabelBrick class must be registered in the internal BrickFactory. Accordingly, we'll need to call the EnsureCustomBrick method in the Program.cs file:


Note: For the Progress Bar control, the BrickFactory registration step can be ignored, since the CreateBrick method for this control returns an instance of PanelBrick, which is a built-in and known. Output is illustrated in the following video. It demonstrates the XRRoundLabel control in the Report Designer, a custom BorderCornerRadius property, and the custom control within the Print Preview:

The registration technique is basically the same for other web-based platforms. Note the differences in how custom control type arrays are passed:


@Html.DevExpress().ReportDesigner(settings => {
    settings.Name = "ReportDesigner1";


For ASP.NET Core applications, custom control types are passed to a designer model created in the controller (using a model builder that implements the IReportDesignerModelBuilder interface):

public class HomeController : Controller {
    // ...
    public IActionResult Designer(
        [FromServices] IReportDesignerModelBuilder reportDesignerModelBuilder, 
        [FromQuery] string reportName) {

        reportName = string.IsNullOrEmpty(reportName) ? "TestReport" : reportName;
        var designerModel = reportDesignerModelBuilder
        return View(designerModel);

DevExpress components for JavaScript frameworks (Angular, React, Vue) are based on aj ASP.NET Core server-side application. This means no client-side code is needed. You have to add custom control types to the ASP.NET Core backend as demonstrated in the code snippet above (and include an SVG template for the toolbar icon in the client application). Yes, it's as simple as that.

In this particular instance, we must call the DevExpress.XtraReports.CustomControls.RoundedCustomControl.EnsureCustomBrick method at application startup in all of our sample projects.

Custom Expression Function Integration

To register a custom expression function in a web application, you need to call one of the following registration methods when you start the application.

Registration Methods

Scope: Only Reporting Components

The CustomFunctions.Register method allows you to use the specified custom functions in expression bindings and calculated fields. Custom functions are displayed in the list of available functions in the Reporting Expression Editor.

DevExpress.XtraReports.Expressions.CustomFunctions.Register(new CustomFormatFunction());

Scope: All DevExpress Components — Data Source Wizard, Query Builder, and Others

If you want your custom function to be available for SQL queries in the Data Source Wizard or elsewhere in the application (outside of our Reporting components), implement the ICustomFunctionOperatorFormattable interface and register the function using the CriteriaOperator.RegisterCustomFunction method. For more information, review the following help topic: Custom Functions.

CriteriaOperator.RegisterCustomAggregate(new CountDistinctCustomAggregate());

Sample Implementation (GitHub): Reporting for ASP.NET Core - How to Implement a Custom Function in the Expression Editor.

What’s New in v23.1 and v23.2

If you have yet to review the features/capabilities introduced in 2023, please visit the following webpages: Reporting, What's New in v23.2  | Reporting, What's New in v23.1.

Free DevExpress Products - Get Your Copy Today

The following free DevExpress product offers remain available. Should you have any questions about the free offers below, please submit a ticket via the DevExpress Support Center at your convenience. We'll be happy to follow-up.