Example T906638
Visible to All Users

How to Create a Custom DevExpress Report Control

Report Control Development Steps

To create a new report control, do the following:

  1. Choose a base class. If you cannot find a suitable control to derive from, inherit a component from the XRControl class.
  2. Create the component's object model. Specify a set of properties and related attributes that determine how properties are serialized and displayed in the Property grid.
  3. Create component designers for Visual Studio and the End User Designer. Designers determine the component's appearance and behavior at design time. Add attributes as necessary.
  4. Choose the base class for the component's “brick” - such as the brick that the base class creates. However, if the component inherits from the XRControl class, there are two options - select VisualBrick as the brick's base class if you require a simple brick or PanelBrick if you need a container.
  5. Specify how the component creates its "brick" and map the component's properties to the brick's characteristics.
  6. Implement the BrickExporter class to render the "brick". Override the methods used for drawing and export.

XRSwissQRBill

Refer to the following document for information on XRSwissQRBill implementation: How to Create a Custom DevExpress Report Control - Swiss QR Bill Implementation.

XRRoundLabel and XRRoundPanel

Refer to the following document for information on XRRoundLabel and XRRoundPanel implementation: How to Create Controls with Rounded Corners.

Examples

WinForms

Run the sample project to invoke the WinForms End-User Report Designer with a toolbox that contains the XRSwissQRBill, XRRoundLabel and XRRoundPanel controls.

The project is in the Examples/CustomControlExample.Win folder. File to review: Program.cs.

ASP.NET Core

Run the sample project to invoke the ASP.NET Core End-User Report Designer with a toolbox that contains the XRRoundLabel, and XRRoundPanel controls.

The project is in the Examples/CustomControlExample.AspNetCore folder. Files to review: Startup.cs and Designer.cshtml.

Files to Review

XRSwissQRBill

XRRoundLabel and XRRoundPanel

Documentation

More Examples

Does this example address your development requirements/objectives?

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

Example Code

DevExpress.XtraReports.CustomControls.SwissQRBill/Readme.md
Code
# How to Create a Custom DevExpress Report Control - Swiss QR Bill Implementation This article documents how we built a custom DevExpress Report control (Swiss QR-Bill Reporting component) and how we addressed issues encountered during development. We hope this information will be of value for those who wish to create their own custom DevExpress Report control. To help demystify the report control development process, this article describes how to create design-time settings, serialize the designer component and related “bricks,” and render a component for print and export. The first section contains general information on the Swiss QR Bill control and describes the requirements for the control itself. The second section details component implementation. ## General Information The Swiss QR Bill is a new payment slip form featuring QR code. Swiss QR Bill consists of the following elements: * receipt; * payment part; * barcode. The invoice may use one of the following layouts: * "Full" invoice printed on an A4 sheet; * "Short" invoice printed on an A6 sheet; * Invoice for continuous printing; * Invoice for printing on individual pages. A "full" invoice contains a receipt whereas a "short" invoice only contains payment info. The component’s **BillKind** property specifies the **PaymentAndReceipt** value for the full invoice and the **PaymentOnly** value for the short invoice. Continuous or individual printing is specified with the **IntegratedMode** property. Invoices are printed (or exported to PDF) on A4 or A6 paper, with a perforation line specified via **BillOption.PreviewSeparatorKind** and **BillOption.PdfSeparatorKind** properties, respectively. The component allows you to change the language and font for any field. The **StringData** property can be used to bind the field to an external data source. ## Report Control Development To create a new report control, you must: 1. Choose a base class. If you cannot find a suitable control to derive from, inherit a component from the **XRControl** class. 2. Create the component's object model. Specify a set of properties and related attributes that determine how properties are serialized and displayed in the Property grid. 3. Create component designers for Visual Studio and the End User Designer. Designers determine the component's appearance and behavior at design time. Add attributes as necessary. 4. Choose the base class for the component's “brick.” An obvious choice is the brick that the base class creates. However, if the component inherits from the **XRControl** class, there are two options - select **VisualBrick** as the brick's base class if you require a simple brick or **PanelBrick** if you need a container. 5. Specify how the component creates its "brick" and map the component's properties to the brick's characteristics. 6. Implement the **BrickExporter** class to render the "brick". Override the methods used for drawing and export. The following sections detail how we built the SwissQRBill component in greater detail. ## Component Implementation Since the SwissQRBill component is an XRControl descendant, it has its own "brick", serialization and an item in the designer's toolbox. ### Design time To add a component to the Visual Studio Toolbox, the component must have the a **ToolBoxItem(true)** attribute. The WinForms End-User Designer requires that the component is registered with the **IToolBoxService**. Handle the **DesignPanelLoaded** event and call the **IToolBoxService.AddToolBoxItem** method to register the component. To implement design-time functionality for the component, add the **Designer** and **XRDesigner** attributes for Visual Studio and the WinForms End-User Designer, respectively. The control's resize rules and smart tag items must be modified as needed. Smart tag items are specified with the **DesignerActionList** objects registered in the Component Designer. The **GetSelectionRulesCore** method modifies the control’s resize rules. Review the code in the following file for more information: [XRSwissQRBillDesignerActionList.cs](../DevExpress.XtraReports.CustomControls.Design/XRSwissQRBillDesignerActionList.cs). When you set up the property grid, pay close attention to expandable objects. In this example, the **ExpandableObjectConverter** descendants are created to override the **ConvertTo** method. The new **ConvertTo** method implementation changes the string displayed in the property grid editor. The **GetProperties** method of the **AddressTypeConverter** removes properties which are not necessary for this address type. Review the code in the following file for more information: [TypeConverters.cs](./SwissQRBill/TypeConverters.cs). ## "Brick" Implementation ### General Concepts [VisualBrick](https://docs.devexpress.com/CoreLibraries/DevExpress.XtraPrinting.VisualBrick) is a basic element used to display data. The VisualBrick element consists of a data model (the brick) and its presentation (the exporter). The exporter renders the "brick" and exports it to different formats. The exporter is specified with the **BrickExporter(Type)** attribute set for the "brick". In this example, we use the **PanelBrickExporter** and **VisualBrickExporter** descendants as exporters. The Draw methods are overridden to implement rendering. The Brick field is used to obtain access to the "brick". To create a "brick", override the **CreateBrick(VisualBrick[] childrenBricks)** method and return the "brick" instance. The **PutStateToBrick(VisualBrick brick, PrintingSystemBase ps)** method maps control properties to "brick" data. Review the code in the following file for more information: [XRSwissQRBill.cs](./SwissQRBill/XRSwissQRBill.cs). ### The Choice of Base Class Swiss QR Control layout is an area with text elements and a barcode in the middle. The primary choices for a base class are a panel, a table, and a text "brick". The panel "brick" can arrange the components inside via its simple structure. For this reason, **SwissQRBillBrick** is based on the **PanelBrick** class, and the exporter is based on the **PanelBrickExporter** class. ### Service Brick Implementation The specification states that the payment portion may contain empty areas marked with corners. To meet this requirement, we created an additional **CornerRectangleBrick** and its exporter – the **CornerRectangleBrickExporter** - which is responsible for drawing corners. This "brick" includes a **BrickType** property - which is overridden to implement correct deserialization. ### Layout Implementation Choose **PanelBrick** as the base class. You can use the **Bricks** property to access its inner "bricks". Inner “brick” coordinates are set relative to the coordinates of the panel itself - relative to point (0, 0). Split the component into _Receipt_ and _Payment Part_ regions. ![QR Swiss Bill Partition](../Images/partition-1.png) Rendering functions return other "bricks" (or "brick" combinations) that are subsequently added to the Bricks collection. * CreateReceiptPart() * CreatePaymentPart() We must now have to render sub-regions, as shown in the image below. ![QR Swiss Bill Sub-Partition](../Images/partition-2.png) 1. CreateReceiptTitle() 2. CreateReceiptInformation() 3. CreateReceiptAmount() 4. CreateReceiptAcceptancePoint() 5. CreatePaymentTitle() 6. CreatePaymentSwissQRCode() 7. CreatePaymentAmount() 8. CreatePaymentInformation() 9. CreatePaymentFurtherInformation() Review the code in the following file for more information: [SwissQRBillBrick.cs](./SwissQRBill/SwissQRBillBrick.cs). ### Exporter Implementation The exporter draws adorners on top of the finished "brick". This allows us to change the appearance in a preview or in an exported PDF file. In this example, the exporter draws perforation lines and additional text. The brick’s **SeparatorKind** option determines what to draw. The same mechanism for drawing a "brick" is used for preview and during PDF export. The main difference is that **IGraphics** passed to the exporter's Draw method is an object with the **IPdfGraphics** interface. ## Serialization ### General Concepts Both the control and the "brick" require serialization. The "brick" only uses xml serialization, and the control implements xml serialization and supports CodeDom serialization - which is mandatory for the Visual Studio Designer. ## Control Serialization The **XtraSerializableProperty** attribute is responsible for serializing the property in xml. Only specify the attribute to serialize a property that returns a simple type. Complex types require a constructor with a **XtraSerializationVisibility** argument type (the most frequently used values are **Hidden**, **Collection**, **Reference**, **Content**). The **DesignerSerializationVisibility** attribute is responsible for the CodeDOM serialization in the Visual Studio Designer. It has only three variants of the related enum - **Hidden**, **Visible**, and **Content**. Mark collections or references with a **Visible** attribute value. The **DefaultValue** attribute determines whether the property value is included in serialization. ### Brick Serialization Only XML serialization is necessary. For correct deserialization, map the "brick’s" text type (the overridden **BrickType** property at the Brick level) to the real type. The **BrickFactory.BrickResolve** method is used for mapping. For an implementation of the **BrickResolve** method, review the code in the following file: [SwissQRBillCustomControl.cs](./SwissQRBillCustomControl.cs) ## Component Use To use the component in the Visual Studio Designer, add it to the Visual Studio Toolbox. To use the component in the End-User Designer, call the **AddSwissQRControlToToolBox** method with the **XRDesignMdiController** passed as an argument. Review the code in the following file for more information: [CustomControlToolBoxRegistrator.cs](../DevExpress.XtraReports.CustomControls.Design/CustomControlToolBoxRegistrator.cs). ## Conclusion You have now created your own custom reporting component. If you have technical questions on this subject, please feel free to contact our support team via the DevExpress [Support Center](https://supportcenter.devexpress.com/). ## Files to Review - [XRSwissQRBill.cs](./SwissQRBill/XRSwissQRBill.cs) - [SwissQRBillCustomControl.cs](./SwissQRBillCustomControl.cs) - [SwissQRBillBrick.cs](./SwissQRBill/SwissQRBillBrick.cs) - [CustomControlToolBoxRegistrator.cs](../DevExpress.XtraReports.CustomControls.Design/CustomControlToolBoxRegistrator.cs) - [XRSwissQRBillDesignerActionList.cs](../DevExpress.XtraReports.CustomControls.Design/XRSwissQRBillDesignerActionList.cs) - [TypeConverters.cs](./SwissQRBill/TypeConverters.cs) ## Documentation - [Use Custom Controls](https://docs.devexpress.com/XtraReports/2607/detailed-guide-to-devexpress-reporting/use-report-controls/use-custom-controls) ## More Examples - [Create a Custom Numeric Label](https://github.com/DevExpress-Examples/Reporting-Create-Custom-Numeric-Label) - [Create a Custom Progress Bar Control](https://github.com/DevExpress-Examples/Reporting_how-to-create-custom-report-controls-e57) - [Add a Custom Control to the End-User Report Designer Toolbox (WPF)](https://github.com/DevExpress-Examples/Reporting_wpf-end-user-report-designer-how-to-register-a-custom-control-in-the-designers-t416384) - [Custom Report Control in the Web End User Designer Toolbox (ASP.NET Web Forms)](https://github.com/DevExpress-Examples/Reporting_aspxreportdesigner-how-to-register-a-custom-control-in-the-designers-toolbox-t209289) - [Custom Report Control in the Web End User Designer Toolbox (ASP.NET MVC)](https://github.com/DevExpress-Examples/Reporting-AspNetMvc-Create-Custom-Control) - [Custom Report Control in the Web End User Designer Toolbox in ASP.NET Core Application](https://github.com/DevExpress-Examples/Reporting-AspNetCore-Create-Custom-Control)
DevExpress.XtraReports.CustomControls.RoundedControls/Readme.md
Code
# How to Create Controls with Rounded Corners This example demonstrates two custom controls. For each control there is a custom "brick" class, and a custom "brick exporter" class. ## Label with Rounded Corners | | Control | Brick | Brick Exporter | | --- | --- | --- | --- | | Class | [XRRoundLabel](Label/XRRoundLabel.cs) | [RoundLabelBrick](Label/RoundLabelBrick.cs) | [RoundLabelBrickExporter](Label/RoundLabelBrickExporter.cs) | | Base Class | [XRLabel](https://docs.devexpress.com/XtraReports/DevExpress.XtraReports.UI.XRLabel) | [LabelBrick](https://docs.devexpress.com/CoreLibraries/DevExpress.XtraPrinting.LabelBrick) | `LabelBrickExporter` | ## Panel with Rounded Corners | | Control | Brick | Brick Exporter | | --- | --- | --- | --- | | Class | [XRRoundPanel](Panel/XRRoundPanel.cs) | [RoundPanelBrick](Panel/RoundPanelBrick.cs) | [RoundLabelBrickExporter](Panel/RoundPanelBrickExporter.cs) | Base Class | [XRPanel](https://docs.devexpress.com/XtraReports/DevExpress.XtraReports.UI.XRPanel) | [PanelBrick](https://docs.devexpress.com/CoreLibraries/DevExpress.XtraPrinting.PanelBrick) | `PanelBrickExporter` | ## Implementation To add a component to the Visual Studio Toolbox, the component must have the a **ToolBoxItem(true)** attribute. Design-time functionality is inherited from the base controls. Each control has the `BorderCornerRadius` public property that defines the degree to which corners are rounded. The `BorderCornerRadius` value is used by the [RoundedBorderPaintHelper](./RoundedBorderPaintHelper.cs) methods to draw background and borders. ### "Brick" The [VisualBrick](https://docs.devexpress.com/CoreLibraries/DevExpress.XtraPrinting.VisualBrick) is a basic element used to display data. The VisualBrick element consists of a data model (the brick) and its presentation (the exporter). The exporter renders the "brick" and exports it to different formats. The exporter is specified with the **BrickExporter(Type)** attribute set for the "brick". In this example, we use the `LabelBrickExporter` and `PanelBrickExporter` descendants as exporters. The `DrawBackground` methods are overridden to implement rendering. The `RoundedBrick` property is used to obtain access to the "brick". ## Serialization ### General Concepts Both the control and the "brick" require serialization. The "brick" only uses XML serialization, and the control implements XML serialization and supports CodeDom serialization - which is mandatory for the Visual Studio Designer. ### Control Serialization The `XtraSerializableProperty` attribute is responsible for serializing the property in xml. Specify the attribute to serialize a property that returns a simple type. Complex types require a constructor with a `XtraSerializationVisibility` argument type. The most frequently used values are the following: **Hidden**, **Collection**, **Reference**, and **Content**. The **DefaultValue** attribute determines whether the property value is included in serialization. ### Brick Serialization Only XML serialization is necessary. For correct deserialization, map the "brick’s" text type (the overridden `BrickType` property at the Brick level) to the real type. The `BrickFactory.BrickResolve` method is used for mapping. For an implementation of the `BrickResolve` method, review the code in the following file: [RoundedCustomControl.cs](../DevExpress.XtraReports.CustomControls.RoundedControls/RoundedCustomControl.cs). ## Toolbox To use the component in the Visual Studio Designer, add it to the Visual Studio Toolbox. To use the component in the End-User Designer, call the `AddRoundedLabelToToolBox` and `AddRoundedPanelToToolBox` methods with the [XRDesignMdiController](https://docs.devexpress.com/XtraReports/DevExpress.XtraReports.UserDesigner.XRDesignMdiController) instance passed as an argument. Review the code in the following file for more information: [CustomControlToolBoxRegistrator.cs](../DevExpress.XtraReports.CustomControls.Design/CustomControlToolBoxRegistrator.cs). ## Result When you run this project, the `XRRoundLabel` and `XRRoundPanel` controls are available in the Toolbox. You can drag-and-drop them to the design area: ![Custom Controls with Rounded Corners](../Images/rounded-controls.png) ## Files to Review - [XRRoundLabel](Label/XRRoundLabel.cs) - [RoundLabelBrick](Label/RoundLabelBrick.cs) - [RoundLabelBrickExporter](Label/RoundLabelBrickExporter.cs) - [XRRoundPanel](Panel/XRRoundPanel.cs) - [RoundPanelBrick](Panel/RoundPanelBrick.cs) - [RoundLabelBrickExporter](Panel/RoundPanelBrickExporter.cs) - [RoundedBorderPaintHelper](./RoundedBorderPaintHelper.cs) - [RoundedCustomControl.cs](../DevExpress.XtraReports.CustomControls.RoundedControls/RoundedCustomControl.cs) - [CustomControlToolBoxRegistrator.cs](../DevExpress.XtraReports.CustomControls.Design/CustomControlToolBoxRegistrator.cs) ## Documentation - [Use Custom Controls](https://docs.devexpress.com/XtraReports/2607/detailed-guide-to-devexpress-reporting/use-report-controls/use-custom-controls) ## More Examples - [Create a Custom Numeric Label](https://github.com/DevExpress-Examples/Reporting-Create-Custom-Numeric-Label) - [Create a Custom Progress Bar Control](https://github.com/DevExpress-Examples/Reporting_how-to-create-custom-report-controls-e57) - [Add a Custom Control to the End-User Report Designer Toolbox (WPF)](https://github.com/DevExpress-Examples/Reporting_wpf-end-user-report-designer-how-to-register-a-custom-control-in-the-designers-t416384) - [Custom Report Control in the Web End User Designer Toolbox (ASP.NET Web Forms)](https://github.com/DevExpress-Examples/Reporting_aspxreportdesigner-how-to-register-a-custom-control-in-the-designers-toolbox-t209289) - [Custom Report Control in the Web End User Designer Toolbox (ASP.NET MVC)](https://github.com/DevExpress-Examples/Reporting-AspNetMvc-Create-Custom-Control) - [Custom Report Control in the Web End User Designer Toolbox in ASP.NET Core Application](https://github.com/DevExpress-Examples/Reporting-AspNetCore-Create-Custom-Control)
DevExpress.XtraReports.CustomControls.SwissQRBill/SwissQRBill/XRSwissQRBill.cs
C#
using System.ComponentModel; using System.Drawing; using DevExpress.Utils.Serializing; using DevExpress.XtraPrinting; using DevExpress.XtraReports.UI; using DevExpress.XtraReports.Expressions; using DevExpress.Utils.Design; using DevExpress.XtraReports.UserDesigner; using DevExpress.XtraPrinting.BarCode; using System.Linq; using System.Diagnostics; using System; using DevExpress.Utils; using DevExpress.Drawing; namespace DevExpress.XtraReports.CustomControls.SwissQRBill { [ToolboxItem(true)] [ToolboxSvgImage("DevExpress.XtraReports.CustomControls.SwissQRBill.Resources.SwissQRBillToolboxSvgImage.svg,DevExpress.XtraReports.CustomControls.SwissQRBill")] [XRDesigner("DevExpress.XtraReports.CustomControls.Design.SwissQRBill.XRSwissQRBillDesigner, DevExpress.XtraReports.CustomControls.Design")] [Designer("DevExpress.XtraReports.CustomControls.Design.SwissQRBill._XRSwissQRBillDesigner, DevExpress.XtraReports.CustomControls.Design")] [XRToolboxSubcategory(0, 7)] [DefaultBindableProperty(nameof(StringData))] #if NET452 [ToolboxBitmap("DevExpress.XtraReports.CustomControls.SwissQRBill.Resources.SwissQRBillToolboxImage.bmp,DevExpress.XtraReports.CustomControls.SwissQRBill")] #endif public partial class XRSwissQRBill : XRControl { public static readonly SizeF InitSizeF = new SizeF(845, 458); QRBillDataItem qrBillDataItem = new QRBillDataItem(); [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override string Text { get => base.Text; set => base.Text = value; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override string TextFormatString { get => base.TextFormatString; set => base.TextFormatString = value; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override string XlsxFormatString { get => base.XlsxFormatString; set => base.XlsxFormatString = value; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override bool WordWrap { get => base.WordWrap; set => base.WordWrap = value; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override bool KeepTogether { get => base.KeepTogether; set => base.KeepTogether = value; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override HorizontalAnchorStyles AnchorHorizontal { get => base.AnchorHorizontal; set => base.AnchorHorizontal = value; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override VerticalAnchorStyles AnchorVertical { get => base.AnchorVertical; set => base.AnchorVertical = value; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override bool CanPublish { get => base.CanPublish; set => base.CanPublish = value; } //Apperance [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override Color BackColor { get => base.BackColor; set => base.BackColor = value; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override Color BorderColor { get => base.BorderColor; set => base.BorderColor = value; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override BorderDashStyle BorderDashStyle { get => base.BorderDashStyle; set => base.BorderDashStyle = value; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override float BorderWidth { get => base.BorderWidth; set => base.BorderWidth = value; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override BorderSide Borders { get => base.Borders; set => base.Borders = value; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override DXFont Font { get => base.Font; set => base.Font = value; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override Color ForeColor { get => base.ForeColor; set => base.ForeColor = value; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override PaddingInfo Padding { get => base.Padding; set => base.Padding = value; } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override StylePriority StylePriority => base.StylePriority; [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override XRControlStyles Styles => base.Styles; [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override TextAlignment TextAlignment { get => base.TextAlignment; set => base.TextAlignment = value; } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public override event BindingEventHandler EvaluateBinding { add { } remove { } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public override event PrintOnPageEventHandler PrintOnPage { add { } remove { } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public override event PreviewMouseEventHandler PreviewMouseMove { add { } remove { } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public override event PreviewMouseEventHandler PreviewMouseDown { add { } remove { } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public override event PreviewMouseEventHandler PreviewMouseUp { add { } remove { } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public override event PreviewMouseEventHandler PreviewClick { add { } remove { } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public override event PreviewMouseEventHandler PreviewDoubleClick { add { } remove { } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public override event DrawEventHandler Draw { add { } remove { } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public override event HtmlEventHandler HtmlItemCreated { add { } remove { } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public override event EventHandler TextChanged { add { } remove { } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public override event UI.ChangeEventHandler SizeChanged { add { } remove { } } [DXDescription("Swiss QR Bill Scripts description"), DisplayName("Swiss QR Bill Scripts"), Category("Behavior"), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), XtraSerializableProperty(XtraSerializationVisibility.Content)] public new XRSwissQRBillScripts Scripts { get { return (XRSwissQRBillScripts)fEventScripts; } } [DisplayName("Bill Kind")] [Description("Bill Kind description")] [Category("Data")] [XtraSerializableProperty] [RefreshProperties(RefreshProperties.All)] [DefaultValue(QRBillKind.PaymentAndReceipt)] public QRBillKind BillKind { get; set; } = QRBillKind.PaymentAndReceipt; public override RectangleF BoundsF { get { return AdaptBounds(base.BoundsF); } set { base.BoundsF = value; } } RectangleF AdaptBounds(RectangleF rect) { if(RootReport != null) { rect.Size = GraphicsUnitConverter.Convert(GetActualSize(), GraphicsDpi.Millimeter, Dpi); } return rect; } [DisplayName("String Data")] [Description("String Data description")] [Category("Data")] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] [Editor(ControlConstants.MultilineStringEditor, ControlConstants.UITypeEditor)] public string StringData { get { return qrBillDataItem.QRCodeData; } set { qrBillDataItem.QRCodeData = value; } } bool ShouldSerializeStringData() => false; [DisplayName("Bill Options")] [Description("Bill Options description")] [Category("Data")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] [XtraSerializableProperty(XtraSerializationVisibility.Content)] public BillOptions BillOptions { get; } = new BillOptions(); [DisplayName("Creditor Information")] [Description("Creditor Information description")] [Category("Data")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] [XtraSerializableProperty(XtraSerializationVisibility.Content)] public Address CreditorInformation { get { return qrBillDataItem.CreditorInformation; } } [DisplayName("Creditor IBAN")] [Description("Creditor IBAN description")] [Category("Data")] [XtraSerializableProperty] public string CreditorIBAN { get { return qrBillDataItem.CreditorAccountNumber.Number; } set { qrBillDataItem.CreditorAccountNumber.Number = value; } } [DisplayName("Reference")] [Description("Reference description")] [Category("Data")] [XtraSerializableProperty] public string Reference { get { return qrBillDataItem.Reference.Number; } set { qrBillDataItem.Reference.Number = value; } } [DisplayName("Debtor Information")] [Description("Debtor Information description")] [Category("Data")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] [XtraSerializableProperty(XtraSerializationVisibility.Content)] public Address DebtorInformation { get { return qrBillDataItem.DebtorInformation; } } [DisplayName("Amount")] [Description("Amount description")] [Category("Data")] [DefaultValue(null)] [XtraSerializableProperty] public double? Amount { get { return qrBillDataItem.Amount; } set { qrBillDataItem.Amount = value; } } [DisplayName("Currency")] [Description("Currency description")] [Category("Data")] [DefaultValue(Currency.CHF)] [XtraSerializableProperty] public Currency Currency { get { return qrBillDataItem.Currency; } set { qrBillDataItem.Currency = value; } } [DisplayName("Additional Information")] [Description("Additional Information description")] [Category("Data")] [DefaultValue("")] [XtraSerializableProperty] public string AdditionalInformation { get { return qrBillDataItem.AdditionalInformation; } set { qrBillDataItem.AdditionalInformation = value; } } [DisplayName("Structured Information")] [Description("Structured Information description")] [Category("Data")] [DefaultValue("")] [XtraSerializableProperty] public string StructuredInformation { get { return qrBillDataItem.StructuredInformation; } set { qrBillDataItem.StructuredInformation = value; } } [DisplayName("Alternative Procedures")] [Description("Alternative Procedures description")] [Category("Data")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] [XtraSerializableProperty(XtraSerializationVisibility.Content)] public AlternativeProcedures AlternativeProcedures { get { return qrBillDataItem.AlternativeProcedures; } } static XRSwissQRBill() { ExpressionBindingDescriptor.SetPropertyDescription(typeof(XRSwissQRBill), nameof(StringData), new ExpressionBindingDescription(new string[] { "BeforePrint" }, 1000, new string[0])); ValidateIncludeQuietZone(); } static void ValidateIncludeQuietZone() { var includeQuietZoneProperty = typeof(QRCodeGenerator).GetProperties().FirstOrDefault(a => a.Name == "IncludeQuietZone"); if(includeQuietZoneProperty == null) Debug.Fail("IncludeQuietZone property is not available. The control may not draw correctly"); } public XRSwissQRBill() { } protected override XRControlScripts CreateScripts() { return new XRSwissQRBillScripts(this); } protected override int DefaultHeight => ConvertFromMMToDpi(Constants.PaymentAndReceiptBounds.Height, GraphicsDpi.HundredthsOfAnInch); protected override int DefaultWidth => ConvertFromMMToDpi(Constants.PaymentAndReceiptBounds.Width, GraphicsDpi.HundredthsOfAnInch); int ConvertFromMMToDpi(float mmValue, float targetDpi) { return (int)GraphicsUnitConverter.Convert(mmValue, GraphicsDpi.Millimeter, targetDpi); } SizeF GetActualSize() { RectangleF actualRect = BillKind == QRBillKind.PaymentOnly ? Constants.PaymentBounds : Constants.PaymentAndReceiptBounds; if(BillOptions.IntegratedMode) actualRect.Height += Constants.IntegratedModeOffset; return actualRect.Size; } protected override VisualBrick CreateBrick(VisualBrick[] childrenBricks) { return new SwissQRBillBrick(this); } protected override void PutStateToBrick(VisualBrick brick, PrintingSystemBase ps) { base.PutStateToBrick(brick, ps); SwissQRBillBrick swissQRBillBrick = brick as SwissQRBillBrick; swissQRBillBrick.BillKind = BillKind; swissQRBillBrick.BillOptions.Assign(BillOptions); swissQRBillBrick.GenerateContent(qrBillDataItem); foreach(var innerBrick in swissQRBillBrick.Bricks) { InitializeInnerBrick(innerBrick, ps); } } void InitializeInnerBrick(Brick brick, PrintingSystemBase ps) { foreach(var innerBrick in brick.Bricks) { InitializeInnerBrick(innerBrick, ps); } brick.Initialize(ps, brick.Rect); } protected override void GetStateFromBrick(VisualBrick brick) { base.GetStateFromBrick(brick); } } }
DevExpress.XtraReports.CustomControls.RoundedControls/Label/XRRoundLabel.cs
C#
using DevExpress.Utils.Design; using DevExpress.Utils.Serializing; using DevExpress.XtraPrinting; using DevExpress.XtraReports.Localization; using DevExpress.XtraReports.UI; using DevExpress.XtraReports.UserDesigner; using System; using System.ComponentModel; namespace DevExpress.XtraReports.CustomControls.RoundBordersControls { [ToolboxItem(true)] [XRToolboxSubcategory(0, 1)] [DefaultBindableProperty(nameof(Text))] [ToolboxSvgImage("DevExpress.XtraReports.CustomControls.RoundedControls.Resources.XRLabel.svg,DevExpress.XtraReports.CustomControls.RoundedControls")] public class XRRoundLabel : XRLabel { int borderCornerRadius = 8; [XtraSerializableProperty] [DefaultValue(8)] [SRCategory(ReportStringId.CatAppearance)] public int BorderCornerRadius { get { return borderCornerRadius; } set { float maxRadius = HeightF / 2 - BorderWidth; if(value <= maxRadius || IsDeserializing) { borderCornerRadius = value; } else { throw new Exception($"Value should be between 0-{(int)maxRadius}"); } } } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] public override BorderSide Borders { get { return BorderSide.All; } set { base.Borders = value; } } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] public override BorderDashStyle BorderDashStyle { get { return BorderDashStyle.Solid; } set { } } public XRRoundLabel() { BorderWidth = 2; TextAlignment = TextAlignment.MiddleCenter; Borders = BorderSide.All; } protected override VisualBrick CreateBrick(VisualBrick[] childrenBricks) { return new RoundLabelBrick(this, null); } protected override void PutStateToBrick(VisualBrick brick, PrintingSystemBase ps) { var roundedBrick = (RoundLabelBrick)brick; roundedBrick.BorderCornerRadius = BorderCornerRadius; base.PutStateToBrick(brick, ps); } } }
DevExpress.XtraReports.CustomControls.RoundedControls/Panel/XRRoundPanel.cs
C#
using DevExpress.Utils.Design; using DevExpress.Utils.Serializing; using DevExpress.XtraPrinting; using DevExpress.XtraReports.Localization; using DevExpress.XtraReports.UI; using DevExpress.XtraReports.UserDesigner; using System; using System.ComponentModel; namespace DevExpress.XtraReports.CustomControls.RoundBordersControls { [ToolboxItem(true)] [ToolboxSvgImage("DevExpress.XtraReports.CustomControls.RoundedControls.Resources.XRPanel.svg,DevExpress.XtraReports.CustomControls.RoundedControls")] [XRToolboxSubcategory(0, 5)] public class XRRoundPanel : XRPanel { int borderCornerRadius = 20; [DefaultValue(20)] [XtraSerializableProperty] [SRCategory(ReportStringId.CatAppearance)] public int BorderCornerRadius { get { return borderCornerRadius; } set { float maxRadius = HeightF / 2 - BorderWidth; if(value <= maxRadius || IsDeserializing) { borderCornerRadius = value; } else { throw new Exception($"Value should be between 0-{(int)maxRadius}"); } } } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] public override BorderSide Borders { get { return BorderSide.All; } set { base.Borders = value; } } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [XtraSerializableProperty(XtraSerializationVisibility.Hidden)] public override BorderDashStyle BorderDashStyle { get { return BorderDashStyle.Solid; } set { } } public XRRoundPanel() { BorderWidth = 2; Borders = BorderSide.All; } protected override VisualBrick CreateBrick(VisualBrick[] childrenBricks) { var panelBrick = new RoundPanelBrick(this); foreach(var item in childrenBricks) panelBrick.Bricks.Add(item); return panelBrick; } protected override void PutStateToBrick(VisualBrick brick, PrintingSystemBase ps) { var roundedBrick = (RoundPanelBrick)brick; roundedBrick.BorderCornerRadius = BorderCornerRadius; base.PutStateToBrick(brick, ps); } } }
Examples/CustomControlExample.Win/Program.cs
C#
using System; using DevExpress.XtraReports.CustomControls; using DevExpress.XtraReports.UI; namespace CustomControlExample.Win { static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { ReportDesignTool designTool = new ReportDesignTool(new Report()); CustomControlToolBoxRegistrator.EnsureSwissQRControl(designTool.DesignRibbonForm.DesignMdiController); CustomControlToolBoxRegistrator.EnsureRoundControls(designTool.DesignRibbonForm.DesignMdiController); designTool.ShowRibbonDesignerDialog(); } } }
Examples/CustomControlExample.AspNetCore/Startup.cs
C#
using CustomControlExample.AspNetCore.Services; using DevExpress.AspNetCore; using DevExpress.AspNetCore.Reporting; using DevExpress.Utils; using DevExpress.XtraReports.CustomControls; using DevExpress.XtraReports.Web.Extensions; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; namespace CustomControlExample.AspNetCore { public class Startup { public Startup(IConfiguration configuration, IWebHostEnvironment hostingEnvironment) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { DeserializationSettings.RegisterTrustedClass(typeof(Report)); DeserializationSettings.RegisterTrustedClass(typeof(DataSource)); services.AddDevExpressControls(); services.AddScoped<ReportStorageWebExtension, CustomReportStorageWebExtension>(); services .AddMvc() .AddNewtonsoftJson(); services.ConfigureReportingServices(configurator => { configurator.ConfigureReportDesigner(designerConfigurator => { designerConfigurator.RegisterDataSourceWizardConfigFileConnectionStringsProvider(); }); configurator.ConfigureWebDocumentViewer(viewerConfigurator => { viewerConfigurator.UseCachedReportSourceBuilder(); }); }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) { DevExpress.XtraReports.Configuration.Settings.Default.UserDesignerOptions.DataBindingMode = DevExpress.XtraReports.UI.DataBindingMode.Expressions; app.UseDevExpressControls(); if(env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); RoundedCustomControl.EnsureCustomBrick(); SwissQRBillCustomControl.EnsureCustomBrick(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); } } }
Examples/CustomControlExample.AspNetCore/Views/Home/Designer.cshtml
Razor
@using DevExpress.XtraReports.CustomControls.RoundBordersControls; @model DevExpress.XtraReports.Web.ReportDesigner.ReportDesignerModel @{ var designerRender = Html.DevExpress().ReportDesigner("reportDesigner") .Height("1000px") .ClientSideEvents(c => { c.CustomizeToolbox("onCustomizeToolbox"); }) .Bind(Model); @designerRender.RenderHtml() string shortTypeNameLabel = typeof(XRRoundLabel).FullName; string fullTypeNameLabel = typeof(XRRoundLabel).AssemblyQualifiedName; string shortTypeNamePanel = typeof(XRRoundPanel).FullName; string fullTypeNamePanel = typeof(XRRoundPanel).AssemblyQualifiedName; } <script type="text/javascript" id="script"> function onCustomizeToolbox(s, e) { customizeToolbox(s, e, '@shortTypeNamePanel', '@fullTypeNamePanel', "XRPanel", "Rounded Panel", 20); customizeToolbox(s, e, '@shortTypeNameLabel', '@fullTypeNameLabel', "XRLabel", "Rounded Label", 8); } </script> <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"/> </g> <defs> <clipPath id="a"> <path fill="#fff" d="M0 0h32v32H0z"/> </clipPath> </defs> </svg> </script> <script type="text/html" id="dxrd-svg-toolbox-devexpress_xtrareports_customcontrols_roundborderscontrols_xrroundpanel"> <svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M23 6H9a3 3 0 0 0-3 3v14a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3V9a3 3 0 0 0-3-3Z" fill="#B8B8B8"/> <rect x="3" y="3" width="26" height="26" rx="5" stroke="#727272" stroke-width="2"/> </svg> </script> <script type="text/html" id="dxrd-svg-toolbox-devexpress_xtrareports_customcontrols_swissqrbill_xrswissqrbill"> <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 32 32" style="enable-background:new 0 0 32 32;" xml:space="preserve"> <style type="text/css"> .Black{fill:#737373;} </style> <path class="Black" d="M10,10H6V6h4V10z M26,6h-4v4h4V6z M10,22H6v4h4V22z M26,26h-4v4h4V26z M30,26h-4v-4h4V26z M20,20h10V3 c0-0.6-0.4-1-1-1H3C2.4,2,2,2.4,2,3v26c0,0.6,0.4,1,1,1h17V20z M20,4h8v8h-8V4z M4,4h8v8H4V4z M12,28H4v-8h8V28z M14,22v-4h-4v-4h4 v-4h4v4h4v4h-4v4H14z"/> </svg> </script> @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" /> <script src="~/js/customControl.js"></script> <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() }
DevExpress.XtraReports.CustomControls.SwissQRBill/SwissQRBillCustomControl.cs
C#
using DevExpress.XtraPrinting; using DevExpress.XtraPrinting.Native; using DevExpress.XtraReports.CustomControls.SwissQRBill; namespace DevExpress.XtraReports.CustomControls { public static class SwissQRBillCustomControl { public static void EnsureCustomBrick() { BrickFactory.BrickResolve += OnBrickResolve; } private static void OnBrickResolve(object sender, BrickResolveEventArgs args) { if(args.Brick != null) return; CreateBrick<SwissQRBillBrick>(args); CreateBrick<CornerRectangleBrick>(args); } static void CreateBrick<T>(DevExpress.XtraPrinting.BrickResolveEventArgs args) where T : class, new() { if(args.Name == typeof(T).Name) { args.Brick = new T() as Brick; } } } }
DevExpress.XtraReports.CustomControls.SwissQRBill/SwissQRBill/SwissQRBillBrick.cs
C#
using DevExpress.XtraPrinting; using DevExpress.XtraPrinting.BarCode; using DevExpress.XtraPrinting.BrickExporters; using DevExpress.XtraReports.UI; using System.Collections.Generic; using System.Drawing; using System.Text; using System.Linq; using System; using DevExpress.Utils.Serializing; using DevExpress.Drawing; using System.Globalization; using DevExpress.Drawing.TextFormatter; namespace DevExpress.XtraReports.CustomControls.SwissQRBill { [BrickExporter(typeof(SwissQRBillBrickExporter))] public partial class SwissQRBillBrick : PanelBrick { static PanelBrick CreatePanelBrick(RectangleF mmBounds) { PanelBrick panelBrick = new PanelBrick() { BackColor = Color.Transparent, Sides = BorderSide.None, BorderStyle = BrickBorderStyle.Inset, Rect = MmToDocConverter.Convert(mmBounds) }; return panelBrick; } static TextBrick CreateTextBrick(string text, DXFont font, RectangleF bounds) { return new TextBrick(CreateBrickStyle(font)) { Rect = bounds, Text = text, }; } static TextBrick CreateBestSizeTextBrick(string text, DXFont font, float maxWidth) { var style = CreateBrickStyle(font); var bestBounds = BestSizeEstimator.GetBoundsToFitText(text, style, maxWidth, GraphicsDpi.Document); return new TextBrick() { Text = text, Style = style, Rect = bestBounds }; } static BrickStyle CreateBrickStyle(DXFont font) { return new XRControlStyle() { Font = font, Padding = new PaddingInfo(1, 1, 0, 0, 96), StringFormat = BrickStringFormat.Create(TextAlignment.TopLeft, true, DXStringTrimming.EllipsisCharacter, false) }; } static float GetFontHeight(DXFont font) { return TextFormatter.CalculateHeightOfLines(font, 1, DXGraphicsUnit.Document); } static DXFont CreateFont(string familyName, int fontSize, DXFontStyle fontStyle) { return new DXFont(familyName, fontSize, fontStyle); } static CultureInfo amountCultureFormat; internal QRBillDataItem BillDataItem { get; set; } [XtraSerializableProperty(XtraSerializationVisibility.Content)] public BillOptions BillOptions { get; } = new BillOptions(); [XtraSerializableProperty] public QRBillKind BillKind { get; set; } Language Language { get { return BillOptions.Language; } } string FontFamily { get { return BillOptions.FontFamily.ToString(); } } public override string BrickType => nameof(SwissQRBillBrick); static SwissQRBillBrick() { amountCultureFormat = (CultureInfo)CultureInfo.InvariantCulture.Clone(); amountCultureFormat.NumberFormat.NumberGroupSeparator = " "; amountCultureFormat.NumberFormat.NumberDecimalSeparator = "."; } public SwissQRBillBrick() : this(null) { } public SwissQRBillBrick(IBrickOwner brickOwner) : base(brickOwner) { BackColor = Color.Transparent; Sides = BorderSide.None; } public void GenerateContent(QRBillDataItem qrBillDataItem) { BillDataItem = qrBillDataItem; VisualBrick paymentPart = CreatePaymentPart(); Bricks.Add(paymentPart); if(BillKind == QRBillKind.PaymentAndReceipt) { VisualBrick receiptPartBrick = CreateReceiptPart(); Bricks.Add(receiptPartBrick); } } TextBrick CreateTitleTextBrick(RectangleF bounds, int fontSize, SectionId localizationKey) { string text = LocalizationData.Instance[Language, localizationKey]; DXFont font = new DXFont(FontFamily, fontSize, Constants.HeaderFontStyle); return new TextBrick(CreateBrickStyle(font)) { Rect = MmToDocConverter.Convert(bounds), Text = text, }; } VisualBrick CreatePaymentPart() { PanelBrick panelBrick = CreatePanelBrick(BoundsCalculator.GetPaymentBounds(this)); panelBrick.Bricks.Add(CreatePaymentTitle()); panelBrick.Bricks.Add(CreatePaymentSwissQRCode()); panelBrick.Bricks.Add(CreatePaymentInformation()); panelBrick.Bricks.Add(CreatePaymentAmount()); panelBrick.Bricks.Add(CreatePaymentFurtherInformation()); return panelBrick; } VisualBrick CreatePaymentTitle() { return CreateTitleTextBrick(Constants.PaymentTitleBounds, Constants.PaymentTitleFontSize, SectionId.PaymentPart); } VisualBrick CreatePaymentInformation() { float sectionBlockOffset = GetFontHeight(CreateFont(FontFamily, Constants.PaymentValueFontSize, Constants.ContentFontStyle)); var panelBrick = CreatePanelBrick(Constants.PaymentInformationBounds); string creditorString = GetCreditorString(); AddRequiredInformationSection(panelBrick, SectionId.AccountPayableTo, creditorString, Constants.PaymentHeadingFontSize, Constants.PaymentValueFontSize, sectionBlockOffset); string creditorReferenceString = GetCreditorReferenceString(); if(!string.IsNullOrWhiteSpace(creditorReferenceString)) AddRequiredInformationSection(panelBrick, SectionId.Reference, creditorReferenceString, Constants.PaymentHeadingFontSize, Constants.PaymentValueFontSize, sectionBlockOffset); string additinalInformationString = GetAdditinalInformationString(); if(!string.IsNullOrWhiteSpace(additinalInformationString)) AddRequiredInformationSection(panelBrick, SectionId.AdditionalInformation, additinalInformationString, Constants.PaymentHeadingFontSize, Constants.PaymentValueFontSize, sectionBlockOffset); string debtorInformationString = GetDebtorInformationString(); AddOptionalInformationSection(panelBrick, SectionId.PayableByNameAddress, debtorInformationString, Constants.PaymentHeadingFontSize, Constants.PaymentValueFontSize, sectionBlockOffset, MmToDocConverter.Convert(Constants.PaymentPayableToCornerSize)); return panelBrick; } string GetAdditinalInformationString() { return string.Join(Environment.NewLine, BillDataItem.AdditionalInformation, BillDataItem.StructuredInformation); } VisualBrick CreatePaymentSwissQRCode() { var panelBrick = CreatePanelBrick(Constants.QRCodeBounds); var generator = new QRCodeGenerator() { Version = QRCodeVersion.Version10, CompactionMode = QRCodeCompactionMode.Byte, ErrorCorrectionLevel = QRCodeErrorCorrectionLevel.M, IncludeQuietZone = false, }; var barCodeBrick = new BarCodeBrick() { Size = panelBrick.Size, Sides = BorderSide.None, AutoModule = true, BinaryData = Encoding.UTF8.GetBytes(BillDataItem.QRCodeData), ShowText = false, Generator = generator, }; ImageBrick logoBrick = new ImageBrick() { Size = panelBrick.Size, Sides = BorderSide.None, BackColor = Color.Transparent, SizeMode = ImageSizeMode.Normal, ImageAlignment = ImageAlignment.MiddleCenter, ImageSource = new DevExpress.XtraPrinting.Drawing.ImageSource(Images.SwissLogo, true), UseImageResolution = true, }; panelBrick.Bricks.Add(barCodeBrick); panelBrick.Bricks.Add(logoBrick); return panelBrick; } VisualBrick CreatePaymentAmount() { return CreateAmountSection(Constants.PaymentAmountBounds, Constants.PaymentHeadingFontSize, Constants.PaymentAmountFontSize, Constants.PaymentPayableToCurrencyWidth, Constants.PaymentAmountCornerSize, true); } VisualBrick CreatePaymentFurtherInformation() { return CreateAlternativeProceduresSectionBrick(BillDataItem.AlternativeProcedures); } VisualBrick CreateAlternativeProceduresSectionBrick(AlternativeProcedures procedures) { if(procedures.IsEmpty) return null; PanelBrick panelBrick = CreatePanelBrick(Constants.ReceiptPartFurtherInformationBounds); DXFont headerFont = CreateFont(FontFamily, Constants.PaymentFurtherInformationFontSize, Constants.HeaderFontStyle); DXFont instructionFont = CreateFont(FontFamily, Constants.PaymentFurtherInformationFontSize, Constants.ContentFontStyle); AddAlternativeProceduresSectionPart(panelBrick, procedures.Name1, procedures.Instruction1, headerFont, instructionFont, 0); if(!procedures.IsSecondPairEmpty) { float y = panelBrick.Bricks.First().Rect.Bottom; AddAlternativeProceduresSectionPart(panelBrick, procedures.Name2, procedures.Instruction2, headerFont, instructionFont, y); List<Brick> instructions = new List<Brick>(panelBrick.Bricks.Where(x => x.Location.X != 0)); float maxX = instructions.Max(x => x.Location.X); instructions.ForEach(x => x.Location = new PointF(maxX, x.Location.Y)); } return panelBrick; } void AddAlternativeProceduresSectionPart(PanelBrick container, string name, string instruction, DXFont headerFont, DXFont instructionFont, float y) { VisualBrick nameHeaderBrick = CreateBestSizeTextBrick($"{name}:", headerFont, container.Size.Width); VisualBrick instructionBrick = CreateBestSizeTextBrick($"{instruction}", instructionFont, container.Size.Width); nameHeaderBrick.Location = new PointF(0, y); instructionBrick.Location = new PointF(nameHeaderBrick.Rect.Right, y); container.Bricks.Add(nameHeaderBrick); container.Bricks.Add(instructionBrick); } VisualBrick CreateReceiptPart() { PanelBrick panelBrick = CreatePanelBrick(BoundsCalculator.GetReceiptBounds(this)); panelBrick.Bricks.Add(CreateReceiptTitle()); panelBrick.Bricks.Add(CreateReceiptInformation()); panelBrick.Bricks.Add(CreateReceiptAmount()); panelBrick.Bricks.Add(CreateReceiptAcceptancePoint()); return panelBrick; } VisualBrick CreateReceiptTitle() { return CreateTitleTextBrick(Constants.ReceiptTitleBounds, Constants.ReceiptTitleFontSize, SectionId.Receipt); } VisualBrick CreateReceiptInformation() { float sectionBlockOffset = GetFontHeight(CreateFont(FontFamily, Constants.ReceiptValueFontSize, Constants.ContentFontStyle)); var panelBrick = CreatePanelBrick(Constants.ReceiptInformationBounds); string creditorString = GetCreditorString(); AddRequiredInformationSection(panelBrick, SectionId.AccountPayableTo, creditorString, Constants.ReceiptHeadingFontSize, Constants.ReceiptValueFontSize, sectionBlockOffset); string creditorReferenceString = GetCreditorReferenceString(); if(!string.IsNullOrWhiteSpace(creditorReferenceString)) AddRequiredInformationSection(panelBrick, SectionId.Reference, creditorReferenceString, Constants.ReceiptHeadingFontSize, Constants.ReceiptValueFontSize, sectionBlockOffset); string debtorInformationString = GetDebtorInformationString(); AddOptionalInformationSection(panelBrick, SectionId.PayableByNameAddress, debtorInformationString, Constants.ReceiptHeadingFontSize, Constants.ReceiptValueFontSize, sectionBlockOffset, MmToDocConverter.Convert(Constants.ReceiptPayableToCornerSize)); return panelBrick; } VisualBrick CreateReceiptAmount() { return CreateAmountSection(Constants.ReceiptAmountBounds, Constants.ReceiptHeadingFontSize, Constants.ReceiptAmountFontSize, Constants.ReceiptPayableToCurrencyWidth, Constants.ReceiptAmountCornerSize, false); } VisualBrick CreateReceiptAcceptancePoint() { string text = LocalizationData.Instance[Language, SectionId.AcceptancePoint]; DXFont font = CreateFont(FontFamily, Constants.ReceiptAcceptancePointFontSize, Constants.HeaderFontStyle); TextBrick acceptanceStringBrick = CreateTextBrick(text, font, MmToDocConverter.Convert(Constants.PaymentAcceptancePointBounds)); acceptanceStringBrick.HorzAlignment = DevExpress.Utils.HorzAlignment.Far; return acceptanceStringBrick; } VisualBrick CreateAmountSection(RectangleF bounds, int headerFontSize, int contentFontSize, float mmCurrencyWidth, SizeF cornerSize, bool applyOffsetOnCorner) { PanelBrick panelBrick = CreatePanelBrick(bounds); DXFont headerFont = new DXFont(FontFamily, headerFontSize, Constants.HeaderFontStyle); DXFont contentFont = new DXFont(FontFamily, contentFontSize, Constants.ContentFontStyle); float currencyWidth = MmToDocConverter.Convert(mmCurrencyWidth); float headerHeight = GetFontHeight(headerFont) + GraphicsUnitConverter.Convert(3, GraphicsDpi.Point, GraphicsDpi.Document); AddAmountSectionHeaders(panelBrick, headerFont, currencyWidth, headerHeight); AddAmountSectionContent(panelBrick, contentFont, currencyWidth, MmToDocConverter.Convert(cornerSize), headerHeight, applyOffsetOnCorner); return panelBrick; } void AddAmountSectionHeaders(PanelBrick container, DXFont headerFont, float currencyWidth, float headerHeight) { string currencyHeaderText = LocalizationData.Instance[Language, SectionId.Currency]; VisualBrick currencyHeaderBrick = CreateTextBrick(currencyHeaderText, headerFont, new RectangleF(0, 0, currencyWidth, headerHeight)); float amountWidth = container.Size.Width - currencyWidth; string amountHeaderText = LocalizationData.Instance[Language, SectionId.Amount]; VisualBrick amountHeaderBrick = CreateTextBrick(amountHeaderText, headerFont, new RectangleF(currencyWidth, 0, amountWidth, headerHeight)); container.Bricks.Add(currencyHeaderBrick); container.Bricks.Add(amountHeaderBrick); } void AddAmountSectionContent(PanelBrick container, DXFont contentFont, float currencyWidth, SizeF cornerSize, float verticalOffset, bool applyOffsetOnCorner) { float contentFontHeight = GetFontHeight(contentFont); string currencyContentText = BillDataItem.Currency.ToString(); VisualBrick currencyContentBrick = CreateTextBrick(currencyContentText, contentFont, new RectangleF(0, verticalOffset, currencyWidth, contentFontHeight)); container.Bricks.Add(currencyContentBrick); string amountString = GetAmountString(); if(string.IsNullOrEmpty(amountString)) { VisualBrick cornerBrick = new CornerRectangleBrick { Rect = new RectangleF(new PointF(container.Rect.Width - cornerSize.Width, applyOffsetOnCorner ? verticalOffset : 0), cornerSize) }; container.Bricks.Add(cornerBrick); } else { float amountWidth = container.Size.Width - currencyWidth; VisualBrick amountContentBrick = CreateTextBrick(amountString, contentFont, new RectangleF(currencyWidth, verticalOffset, amountWidth, contentFontHeight)); container.Bricks.Add(amountContentBrick); } } string GetAmountString() { return BillDataItem.Amount == null ? "" : BillDataItem.Amount.Value.ToString("N02", amountCultureFormat); } void AddRequiredInformationSection(PanelBrick container, SectionId headerLocalizationKey, string contextText, int headerFontSize, int contentFontSize, float startOffset) { string headerText = LocalizationData.Instance[Language, headerLocalizationKey]; var headerBrick = CreateBestSizeTextBrick(headerText, new DXFont(FontFamily, headerFontSize, Constants.HeaderFontStyle), container.Rect.Width); var contentBrick = CreateBestSizeTextBrick(contextText, new DXFont(FontFamily, contentFontSize, Constants.ContentFontStyle), container.Rect.Width); AddSectionPartToContainer(container, headerBrick, contentBrick, startOffset); } void AddOptionalInformationSection(PanelBrick container, SectionId headerLocalizationKey, string contentText, int headerFontSize, int contentFontSize, float startOffset, SizeF cornerSize) { string headerText = LocalizationData.Instance[Language, headerLocalizationKey]; VisualBrick headerBrick = CreateBestSizeTextBrick(headerText, new DXFont(FontFamily, headerFontSize, Constants.HeaderFontStyle), container.Rect.Width); VisualBrick contentBrick = string.IsNullOrWhiteSpace(contentText) ? new CornerRectangleBrick() { Rect = new RectangleF(PointF.Empty, cornerSize) } : (VisualBrick)CreateBestSizeTextBrick(contentText, new DXFont(FontFamily, contentFontSize, Constants.ContentFontStyle), container.Rect.Width); AddSectionPartToContainer(container, headerBrick, contentBrick, startOffset); } void AddSectionPartToContainer(PanelBrick container, VisualBrick headerBrick, VisualBrick contentBrick, float offset) { float actualY = container.Bricks.Any() ? container.Bricks.Last().Rect.Bottom + offset : 0; headerBrick.Location = new PointF(0, actualY); contentBrick.Location = new PointF(0, headerBrick.Rect.Bottom); container.Bricks.Add(headerBrick); container.Bricks.Add(contentBrick); } string GetCreditorString() { return string.Join(Environment.NewLine, BillDataItem.CreditorAccountNumber.ConvertToPresentationString(), BillDataItem.CreditorInformation.ConvertToPresentationString()); } string GetDebtorInformationString() { return BillDataItem.DebtorInformation.ConvertToPresentationString(); } string GetCreditorReferenceString() { return BillDataItem.Reference == null ? "" : BillDataItem.Reference.ConvertToPresentationString(); } } }
DevExpress.XtraReports.CustomControls.Design/CustomControlToolBoxRegistrator.cs
C#
using System.Drawing.Design; using DevExpress.XtraReports.CustomControls.RoundBordersControls; using DevExpress.XtraReports.CustomControls.SwissQRBill; using DevExpress.XtraReports.UI; using DevExpress.XtraReports.UserDesigner; namespace DevExpress.XtraReports.CustomControls { public static class CustomControlToolBoxRegistrator { public static void EnsureSwissQRControl(XRDesignMdiController designMdiController) { SwissQRBillCustomControl.EnsureCustomBrick(); AddSwissQRControlToToolBox(designMdiController); } public static void EnsureRoundControls(XRDesignMdiController designMdiController) { RoundedCustomControl.EnsureCustomBrick(); AddRoundedLabelToToolBox(designMdiController); AddRoundedPanelToToolBox(designMdiController); } public static void AddRoundedLabelToToolBox(XRDesignMdiController designMdiController) { AddControlToToolBox<XRRoundLabel>(designMdiController, "Rounded Label"); } public static void AddRoundedPanelToToolBox(XRDesignMdiController designMdiController) { AddControlToToolBox<XRRoundPanel>(designMdiController, "Rounded Panel"); } public static void AddSwissQRControlToToolBox(XRDesignMdiController designMdiController) { AddControlToToolBox<XRSwissQRBill>(designMdiController, "Swiss QR Bill"); } static void AddControlToToolBox<TControl>(XRDesignMdiController designMdiController, string displayName) where TControl : XRControl { designMdiController.DesignPanelLoaded += (s, e) => { IToolboxService toolboxService = (IToolboxService)e.DesignerHost.GetService(typeof(IToolboxService)); var toolboxItem = new ToolboxItem(typeof(TControl)) { DisplayName = displayName }; toolboxService.AddToolboxItem(toolboxItem); }; } } }
DevExpress.XtraReports.CustomControls.Design/XRSwissQRBillDesignerActionList.cs
C#
using System.ComponentModel; using System.Drawing.Design; using System.ComponentModel.Design; using DevExpress.XtraReports.Design; using DevExpress.XtraReports.Design.Expressions; using DevExpress.XtraReports.CustomControls.SwissQRBill; using DevExpress.Utils; namespace DevExpress.XtraReports.CustomControls.Design.SwissQRBill { public class XRSwissQRBillDesignerActionList : XRControlBaseDesignerActionList { public string StringData { get { return ((XRSwissQRBill)Component).StringData; } set { SetPropertyValue(nameof(XRSwissQRBill.StringData), value); } } [Editor(typeof(ExpressionValueEditor), typeof(UITypeEditor))] [AdditionalEditor(typeof(PopupExpressionValueEditor))] [TypeConverter(typeof(ExpressionPropertyTypeConverter))] public string StringDataExpression { get { return GetExpression(nameof(XRSwissQRBill.StringData)); } set { SetExpression(nameof(XRSwissQRBill.StringData), value); } } public XRSwissQRBillDesignerActionList(XRControlDesigner designer) : base(designer) { } protected override void FillActionItemCollection(DesignerActionItemCollection actionItems) { AddPropertyItem(actionItems, nameof(StringData), nameof(XRSwissQRBill.StringData)); DesignerActionPropertyItem item; if(TryCreatePropertyItem(nameof(StringDataExpression), string.Empty, out item)) actionItems.Add(item); } } }
DevExpress.XtraReports.CustomControls.SwissQRBill/SwissQRBill/TypeConverters.cs
C#
using System; using System.ComponentModel; using System.Globalization; using System.Linq; namespace DevExpress.XtraReports.CustomControls.SwissQRBill { public class BillOptionsTypeConverter : ExpandableObjectConverter { public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if(destinationType == typeof(string) && value is BillOptions) return "(Options)"; return base.ConvertTo(context, culture, value, destinationType); } } public class SwissQRBillScriptsTypeConverter : ExpandableObjectConverter { public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if(destinationType == typeof(string) && value is XRSwissQRBillScripts) return "(Swiss QR Bill Scripts)"; return base.ConvertTo(context, culture, value, destinationType); } } public class AlternativeProceduresTypeConverter : ExpandableObjectConverter { public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if(destinationType == typeof(string) && value is AlternativeProcedures) return $"({(value).GetType().Name})"; return base.ConvertTo(context, culture, value, destinationType); } } public class AddressTypeConverter : ExpandableObjectConverter { readonly string[] CombinedSpecificProps = new string[] { nameof(Address.AddressLine1), nameof(Address.AddressLine2) }; readonly string[] StructuredSpecificProps = new string[] { nameof(Address.CountryCode), nameof(Address.BuildingNumber), nameof(Address.PostalCode), nameof(Address.Street), nameof(Address.Town) }; public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if(destinationType == typeof(string) && value is Address address) return $"({address.AddressType})"; return base.ConvertTo(context, culture, value, destinationType); } public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) { Address address = value as Address; if(address != null) { var propertiesCollection = base.GetProperties(context, value, attributes).Cast<PropertyDescriptor>().ToList(); if(address.AddressType == AddressType.Structured) propertiesCollection.RemoveAll(p => CombinedSpecificProps.Contains(p.Name)); else propertiesCollection.RemoveAll(p => StructuredSpecificProps.Contains(p.Name)); return new PropertyDescriptorCollection(propertiesCollection.ToArray()); } return base.GetProperties(context, value, attributes); } } }
DevExpress.XtraReports.CustomControls.RoundedControls/Label/RoundLabelBrick.cs
C#
using DevExpress.Utils.Serializing; using DevExpress.XtraPrinting; using DevExpress.XtraPrinting.BrickExporters; using System.ComponentModel; namespace DevExpress.XtraReports.CustomControls.RoundBordersControls { [BrickExporter(typeof(RoundLabelBrickExporter))] public class RoundLabelBrick : LabelBrick { public override string BrickType => nameof(RoundLabelBrick); public RoundLabelBrick() { } public RoundLabelBrick(IBrickOwner brickOwner) : base(brickOwner) { } public RoundLabelBrick(IBrickOwner brickOwner, BrickStyle style) : base(brickOwner, style) { } [DefaultValue(8)] [XtraSerializableProperty] public int BorderCornerRadius { get; set; } = 8; } }
DevExpress.XtraReports.CustomControls.RoundedControls/Label/RoundLabelBrickExporter.cs
C#
using DevExpress.Drawing; using DevExpress.XtraPrinting; using DevExpress.XtraPrinting.BrickExporters; using System.Drawing; using System.Drawing.Drawing2D; namespace DevExpress.XtraReports.CustomControls.RoundBordersControls { public class RoundLabelBrickExporter : LabelBrickExporter { RoundLabelBrick RoundedBrick { get { return Brick as RoundLabelBrick; } } protected override void DrawBackground(IGraphics gr, RectangleF rect) { if(RoundedBrick.BorderCornerRadius > 0) { DXSmoothingMode oldSmoothingMode = gr.SmoothingMode; try { gr.SmoothingMode = DXSmoothingMode.AntiAlias; RoundedBorderPaintHelper.DrawRoundedBackGround(gr, rect, Style, BrickPaint, RoundedBrick.BorderCornerRadius); RoundedBorderPaintHelper.DrawRoundedBorders(gr, rect, Style, BrickPaint, RoundedBrick.BorderCornerRadius); } finally { gr.SmoothingMode = oldSmoothingMode; } return; } base.DrawBackground(gr, rect); } } }
DevExpress.XtraReports.CustomControls.RoundedControls/Panel/RoundPanelBrick.cs
C#
using DevExpress.Utils.Serializing; using DevExpress.XtraPrinting; using DevExpress.XtraPrinting.BrickExporters; using System.ComponentModel; namespace DevExpress.XtraReports.CustomControls.RoundBordersControls { [BrickExporter(typeof(RoundPanelBrickExporter))] public class RoundPanelBrick : PanelBrick { public override string BrickType => nameof(RoundPanelBrick); public RoundPanelBrick() { } public RoundPanelBrick(IBrickOwner brickOwner) : base(brickOwner) { } public RoundPanelBrick(IBrickOwner brickOwner, BrickStyle style) : base(brickOwner, style) { } [DefaultValue(20)] [XtraSerializableProperty] public int BorderCornerRadius { get; set; } = 20; } }
DevExpress.XtraReports.CustomControls.RoundedControls/Panel/RoundPanelBrickExporter.cs
C#
using DevExpress.Drawing; using DevExpress.XtraPrinting; using DevExpress.XtraPrinting.BrickExporters; using System.Drawing; using System.Drawing.Drawing2D; namespace DevExpress.XtraReports.CustomControls.RoundBordersControls { public class RoundPanelBrickExporter : PanelBrickExporter { RoundPanelBrick RoundedBrick { get { return Brick as RoundPanelBrick; } } protected override void DrawBackground(IGraphics gr, RectangleF rect) { if(RoundedBrick.BorderCornerRadius > 0) { DXSmoothingMode oldSmoothingMode = gr.SmoothingMode; try { gr.SmoothingMode = DXSmoothingMode.AntiAlias; RoundedBorderPaintHelper.DrawRoundedBackGround(gr, rect, Style, BrickPaint, RoundedBrick.BorderCornerRadius); RoundedBorderPaintHelper.DrawRoundedBorders(gr, rect, Style, BrickPaint, RoundedBrick.BorderCornerRadius); } finally { gr.SmoothingMode = oldSmoothingMode; } return; } base.DrawBackground(gr, rect); } } }
DevExpress.XtraReports.CustomControls.RoundedControls/RoundedBorderPaintHelper.cs
C#
using DevExpress.Drawing; using DevExpress.XtraPrinting; using DevExpress.XtraPrinting.Native; using System; using System.Drawing; namespace DevExpress.XtraReports.CustomControls { public static class RoundedBorderPaintHelper { public static void DrawRoundedBackGround(IGraphics gr, RectangleF rect, BrickStyle Style, BrickPaintBase painter, int radius) { var borderWidth = GraphicsUnitConverter.Convert(Style.BorderWidth, GraphicsDpi.DeviceIndependentPixel, GraphicsDpi.UnitToDpi((GraphicsUnit)gr.PageUnit)); rect = RectangleF.Inflate(rect, -borderWidth / 2, -borderWidth / 2); DXGraphicsPath path = BuildPath(gr, rect, radius); gr.FillPath(painter.GetBrush(Style.BackColor), path); } public static void DrawRoundedBorders(IGraphics gr, RectangleF rect, BrickStyle Style, BrickPaintBase painter, int radius) { float borderWidth = GraphicsUnitConverter.Convert(Style.BorderWidth, GraphicsDpi.DeviceIndependentPixel, GraphicsDpi.UnitToDpi((GraphicsUnit)gr.PageUnit)); if(borderWidth == 0) return; rect = RectHelper.AdjustBorderRect(rect, BorderSide.All, borderWidth, Style.BorderStyle); rect.Inflate(-borderWidth / 2, -borderWidth / 2); borderWidth = Math.Min(borderWidth, Math.Min(rect.Width, rect.Height)); DXGraphicsPath path = BuildPath(gr, rect, radius); gr.DrawPath(painter.GetPen(Style.BorderColor, borderWidth), path); } static DXGraphicsPath BuildPath(IGraphics gr, RectangleF rect, int radius) { var path = new DXGraphicsPath(); radius = GraphicsUnitConverter.Convert(radius, GraphicsDpi.DeviceIndependentPixel, GraphicsDpi.UnitToDpi((GraphicsUnit)gr.PageUnit)); // Ensure the radius does not exceed half the height of the rectangle to prevent arc overlap radius = Math.Min(radius, (int)Math.Floor(rect.Height / 2)); radius = Math.Min(radius, (int)Math.Floor(rect.Width / 2)); path.AddLine(rect.Left + radius, rect.Top, rect.Right - radius, rect.Top); path.AddArc(rect.Right - 2 * radius, rect.Top, 2 * radius, 2 * radius, 270, 90); path.AddLine(rect.Right, rect.Top + radius, rect.Right, rect.Bottom - radius); path.AddArc(rect.Right - 2 * radius, rect.Bottom - 2 * radius, 2 * radius, 2 * radius, 0, 90); path.AddLine(rect.Right - radius, rect.Bottom, rect.Left + radius, rect.Bottom); path.AddArc(rect.Left, rect.Bottom - 2 * radius, 2 * radius, 2 * radius, 90, 90); path.AddLine(rect.Left, rect.Bottom - radius, rect.Left, rect.Top + radius); path.AddArc(rect.Left, rect.Top, 2 * radius, 2 * radius, 180, 90); path.CloseFigure(); return path; } } }
DevExpress.XtraReports.CustomControls.RoundedControls/RoundedCustomControl.cs
C#
using DevExpress.XtraPrinting; using DevExpress.XtraPrinting.Native; using DevExpress.XtraReports.CustomControls.RoundBordersControls; namespace DevExpress.XtraReports.CustomControls { public static class RoundedCustomControl { public static void EnsureCustomBrick() { BrickFactory.BrickResolve += OnBrickResolve; } private static void OnBrickResolve(object sender, BrickResolveEventArgs args) { if(args.Brick != null) return; CreateBrick<RoundLabelBrick>(args); CreateBrick<RoundPanelBrick>(args); } static void CreateBrick<T>(DevExpress.XtraPrinting.BrickResolveEventArgs args) where T : class, new() { if(args.Name == typeof(T).Name) { args.Brick = new T() as Brick; } } } }

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.