Create and Register a Custom Control in the Report Designer Toolbox (ASP.NET MVC)

  • 5 minutes to read

This topic explains how to create a custom report control inherited from the XRLabel control and register the control in the End-User Report Designer Toolbox .

View Example: Custom Report Control in the Web End User Designer Toolbox (ASP.NET MVC)

Prerequisites

Start with an existing Web Reporting application or create a new application as described in the following help topics:

Create and Register a Custom Control in Visual Studio

To create a custom label control, do the following:

  1. Add a new class (the NumericLabel class in this example), derive it from the XRLabel class, and declare a new property. Override the PutStateToBrick protected method to assign the value to the VisualBrick.Text property:

    using DevExpress.Utils.Serializing;
    using DevExpress.XtraPrinting;
    using DevExpress.XtraReports.UI;
    using System.ComponentModel;
    
    namespace Reporting_AspNetMvc_Create_Custom_Control
    {
        public class NumericLabel : XRLabel
        {
            [Browsable(true), Bindable(false), Category("Data")]
            [XtraSerializableProperty]
            [DefaultValue("")]
            [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
            EditorBrowsable(EditorBrowsableState.Always)]
            public int Number { get; set; }
    
            // Render the control in the Designer's Preview and in the document.
            protected override void PutStateToBrick(VisualBrick brick, PrintingSystemBase ps)
            {
                base.PutStateToBrick(brick, ps);
                brick.Text = this.Number.ToString();
            }
        }
    }
    
NOTE

The Visual Studio Report Designer in ASP.NET project does not display a custom control in the Toolbox.

Register a Custom Control in the Web End-User Report Designer

The following steps demonstrate how to register a custom control in the Web Report Designer Toolbox.

  1. Add a new NumericLabel folder to the project. Create two nested folders - js and css.
  2. Add a control’s icon to the css folder. The icon is an image file (PNG format, 24x24 pixels) that is shown in the Report Designer Toolbox.
  3. Add the custom-label.css file to the css folder with the following content:

    .dxrd-image-reporting_aspnetmvc_create_custom_control_numericlabel {
        background-image: url(NumericLabel.png);
        background-repeat: no-repeat;
    }
    
    NOTE

    The CSS class name is based on the following pattern:

    .dxrd-image-<namespace in lowercase>_<class name>

  4. Create a content template for the custom control, as illustrated in the following code snippet:

    <template id='numeric-label-content'>
        <div data-bind="styleunit: { lineHeight: contentSizes().height / _context.zoom() }" 
                                    style="box-sizing: border-box;
                                    letter-spacing: normal; width: 100%">
            <div class="dxrd-control-content" 
                data-bind="text: displaySomeProperty, style: contentCss"></div>
        </div>
    </template>
    
  5. Add the numeric-label.js file to the NumericLabel/js folder with the following JavaScript code:

    // Create and register a custom control.
    function customizeToolbox(s, e, shortTypeName, fullTypeName) {
        // Get info objects which are common for most controls.
        // Info objects which are unnecessary for the current implementation are commented out.
        var controlsFactory = e.ControlsFactory;
        var labelInfo = controlsFactory.getControlInfo("XRLabel");
        //var textInfo = controlsFactory.getPropertyInfo("XRLabel", "Text");
        //var stringInfo = controlsFactory.getPropertyInfo("XRLabel", "Text");
        //var objectEditor = controlsFactory.getPropertyInfo("XRLabel", "Size").editor;
        var numberInfo = controlsFactory.getPropertyInfo("XRLabel", "Angle");
    
        var customNumberSerializationInfo = $.extend({}, numberInfo, {
            propertyName: "Number",
            modelName: "@Number",
            displayName: "Number",
            defaultVal: 0,
            localizationId: ""
        }
        );
    
        // Create the NumericLabel surface.
        var NumericLabelSurface = (function (_super) {
            __extends(NumericLabelSurface, _super);
            function NumericLabelSurface(control, context) {
                _super.call(this, control, context);
                this.contenttemplate = "numeric-label-content";
                this.displaySomeProperty = ko.computed(function () {
                    var text = control["Number"] && control["Number"]();
                    return text ? text : (control["text"] && control["text"]() || "");
                });
            }
            return NumericLabelSurface;
        })(labelInfo.surfaceType);
    
        // Create an object with information about the NumericLabel toolbox item.
        var numericLabelInfo = controlsFactory.inheritControl("XRLabel", {
            surfaceType: NumericLabelSurface,
            defaultVal: {
                "@ControlType": fullTypeName,
                "@SizeF": "200,50"
            },
            toolboxIndex: 1,
            info: [customNumberSerializationInfo],
            popularProperties: ["Number"]
        });
    
        // Register the NumericLabel in the Report Designer Toolbox.
        controlsFactory.registerControl(shortTypeName, numericLabelInfo);
    
        // Add the "Number" property to the Property panel's "Expressions" tab.
        var defaultExpression = controlsFactory.getPropertyInfo(shortTypeName, "Expression")
        defaultExpression.expressionName = "Number"
        // Specify the event in which the property should be available.
        controlsFactory.setExpressionBinding(shortTypeName, "Number",
            controlsFactory._beforePrintPrintOnPage);
        // Add the "Number" property to the Property panel's "Data Bindings" section.
        var dataBindings = controlsFactory.getPropertyInfo(shortTypeName, "Data Bindings");
        dataBindings.allDataBindings.push("Number");
        // Specify the default data binding property.
        var defaultBinding = controlsFactory.getPropertyInfo(shortTypeName, "Data Binding");
        defaultBinding.bindingName = "Number";
        // Add the "Number" property to the Property Grid's Data category.
        s.AddToPropertyGrid("Data", customNumberSerializationInfo);
    }
    
  6. Add the custom-label.js script file to the page and handle the client-side ASPxClientReportDesigner.CustomizeToolbox event:

    NOTE

    You may need to add the @Import directive to specify the CustomLabel class namespace.

    @using Reporting_AspNetMvc_Create_Custom_Control
    
    @*A style that specifies the toolbox item icon.*@
    <link rel="stylesheet" href="~/NumericLabel/css/numeric-label.css" />
    
    @*A template used to display the NumericLabel control on the Designer surface.*@
    <template id='numeric-label-content'>
        <div data-bind="styleunit: { lineHeight: contentSizes().height / _context.zoom() }" 
             style="box-sizing: border-box;
             letter-spacing: normal; width: 100%">
            <div class="dxrd-control-content" data-bind="text: displaySomeProperty, 
                 style: contentCss"></div>
        </div>
    </template>
    
    @*Add TypeScript helper functions library.*@
    <script src="~/NumericLabel/js/tslib.min.js"></script>
    @*The code that creates and registers the NumericLabel control.*@
    <script src="~/NumericLabel/js/numeric-label.js"></script>
    
    @{
        //Get the NumericLabel control's type name.
        string shortTypeName = typeof(NumericLabel).FullName;
        string fullTypeName = typeof(NumericLabel).AssemblyQualifiedName;
    }
    
    <script type="text/javascript" id="script">
        function onCustomizeToolbox(s, e) {
            customizeToolbox(s, e, '@shortTypeName', '@fullTypeName');
            // Hide the Text property in the NumericLabel control's Property panel.
            s.GetPropertyInfo('@shortTypeName', "Text").visible = false;
            // Hide the XRLabel control in the Toolbox.
            var info = e.ControlsFactory.getControlInfo("XRLabel");
            info.isToolboxItem = false;
        }
    </script>
    
    @Html.DevExpress().ReportDesigner(settings =>
    {
        settings.Name = "ReportDesigner1";
        settings.ClientSideEvents.CustomizeToolbox = "onCustomizeToolbox";
    }).BindToUrl("TestReport").GetHtml()
    

Use LibMan to Manage Client-Side Libraries

Right-click the project in the Solution Explorer and select Manage Client-Side Libraries to open the libman.json file.

Manage Client-Side Libraries

Paste the following content and save the file:

{
  "version": "1.0",
  "defaultProvider": "cdnjs",
  "libraries": [
    {
      "provider": "cdnjs",
      "library": "tslib@2.2.0",
      "destination": "NumericLabel/js/",
      "files": [
        "tslib.min.js"
      ]
    },

  ]
}
NOTE

If your application already uses the library listed above, remove duplicate library reference to ensure it is registered only once.

For more information on LibMan, review the following article: Use LibMan with ASP.NET Core in Visual Studio.

Remove an Existing Control from the Toolbox

You can use the CustomizeToolbox event to remove an existing control from the Toolbox. Use the getControlInfo method of the event argument’s ASPxClientReportDesignerCustomizeToolboxEventArgs.ControlsFactory property to obtain the specified control and set the IElementMetadata.isToolboxItem property to false:

        function onCustomizeToolbox(s, e) {
            customizeToolbox(s, e, '@shortTypeName', '@fullTypeName');
            // Hide the Text property in the NumericLabel control's Property panel.
            s.GetPropertyInfo('@shortTypeName', "Text").visible = false;
            // Hide the XRLabel control in the Toolbox.
            var info = e.ControlsFactory.getControlInfo("XRLabel");
            info.isToolboxItem = false;
        }

Run the Application

Run the application to invoke the End-User Designer. Create a new report, and drop the NumericLabel control from the Toolbox to the design surface:

See Also