xtrareports-403247-feature-guide-to-devexpress-reports-reporting-api-use-helper-classes.md
This section lists helper classes (utilities) you can use to customize report rendering and implement additional functionality in reporting applications.
GraphicsUnitConverterConverts values to different measurement units.
The following code snippet calculates the clipping region of the drawing surface. The Graphics measurement unit is Document and the report measurement unit is specified by the XtraReport.ReportUnit property.
var clipBounds = GraphicsUnitConverter.Convert(report.PageSize, report.Dpi, GraphicsDpi.Document);
Dim clipBounds = GraphicsUnitConverter.Convert(report.PageSize, report.Dpi, GraphicsDpi.Document)
For additional information, review the following help topic: Report Units of Measurement.
BestSizeEstimatorAllows you to find the optimal boundaries for a font or get a font that fits the boundaries.
The following code adjusts the font to fit the XRLabel:
label.Font = BestSizeEstimator.GetFontToFitBounds(label);
label.Font = BestSizeEstimator.GetFontToFitBounds(label)
DataSourceManagerContains methods that allow you to manage report data sources at runtime.
When you create a reporting application, you might need to modify or configure data sources for your reports at runtime. Refer to the following topic for more information: Manage Data Sources at Runtime.
The following code snippet replaces the report’s data sources with the test data sources:
foreach(var ods in DataSourceManager.GetDataSources<ObjectDataSource>(report)) {
TestObjectDataSource tds = new TestObjectDataSource(ods.Container) {
Constructor = ods.Constructor,
DataMember = ods.DataMember,
DataSource = ods.DataSource,
Name = ods.Name
};
tds.Parameters.AddRange(ods.Parameters);
DataSourceManager.ReplaceDataSource(report, ods, tds);
}
For Each ods In DataSourceManager.GetDataSources(Of ObjectDataSource)(report)
Dim tds As New TestObjectDataSource(ods.Container) With {
.Constructor = ods.Constructor,
.DataMember = ods.DataMember,
.DataSource = ods.DataSource,
.Name = ods.Name
}
tds.Parameters.AddRange(ods.Parameters)
DataSourceManager.ReplaceDataSource(report, ods, tds)
Next ods
BrickSelectorSelects bricks from a document or document page(s).
The methods stored in the BrickSelector class allow you to select bricks:
GetBricks(page) - returns all bricks on a page.
GetBricksByXRControl(page, control) - returns bricks generated by a specific report control.
GetBricksByTag(page, tag) - returns bricks by tag.
After a report is generated, its layout is transformed into a document that consists of bricks. A brick is a visual element that is the rendered output of a report control. Bricks are placed on document pages and contain visual properties such as bounds, borders, text, colors, and visibility. Since the layout is determined prior to the generation of bricks, they do not affect layout calculation.
If you need to change the layout configuration, modify the report controls prior to document generation.
To post-process the final document - modify bricks.
Most brick-based customizations are made in the XRControl.AfterPrint event, after the document is fully created.
Use bricks in the following cases:
Adjust visual properties after layout is complete.
Add or remove borders dynamically.
Align elements across pages.
Detect first/last page of a group.
Create custom navigation links.
Hide or modify specific rendered elements.
Tip
Modifications are page-specific. If the same control appears on multiple pages, process each page separately.
For additional information on bricks, refer to the following help topic: Bricks.
Post-process a rendered document and add a vertical border line to the last cell in each row (for example, to complete a crosstab grid when design-time borders are not enough).
using System.Drawing;
using System.Linq;
private void XtraReport1_AfterPrint(object sender, EventArgs e) {
// Handle AfterPrint.
foreach (DevExpress.XtraPrinting.Page page in Pages) {
// For each page, get bricks generated by a specific XRControl (crossTabDataCell1).
var bricks = DevExpress.XtraPrinting.BrickSelector
.GetBricksByXRControl(page, crossTabDataCell1);
// Group bricks by row coordinate.
var rows = bricks.GroupBy(b => b.Rect.Top);
foreach (var row in rows) {
// Identify the last brick in the row.
var lastBrick = (DevExpress.XtraPrinting.VisualBrick)
row.OrderBy(b => b.Rect.Left).Last();
// Apply the required border settings to that brick.
lastBrick.Sides =
DevExpress.XtraPrinting.BorderSide.Right |
DevExpress.XtraPrinting.BorderSide.Bottom;
lastBrick.BorderWidth = 1;
lastBrick.BorderColor = Color.Black;
}
}
}
Imports System.Drawing
Imports System.Linq
Private Sub XtraReport1_AfterPrint(ByVal sender As Object, ByVal e As EventArgs)
' Handle AfterPrint.
For Each page As DevExpress.XtraPrinting.Page In Pages
' For each page, get bricks generated by a specific XRControl (crossTabDataCell1).
Dim bricks = DevExpress.XtraPrinting.BrickSelector.GetBricksByXRControl(page, crossTabDataCell1)
' Group bricks by row coordinate.
Dim rows = bricks.GroupBy(Function(b) b.Rect.Top)
For Each row In rows
' Identify the last brick in the row.
Dim lastBrick = CType(row.OrderBy(Function(b) b.Rect.Left).Last(), DevExpress.XtraPrinting.VisualBrick)
' Apply the required border settings to that brick.
lastBrick.Sides = DevExpress.XtraPrinting.BorderSide.Right Or DevExpress.XtraPrinting.BorderSide.Bottom
lastBrick.BorderWidth = 1
lastBrick.BorderColor = Color.Black
Next row
Next page
End Sub
When detail content height varies, make each printed line uniform by adjusting all bricks in that line to the maximum height in the group, without increasing every row globally.
using DevExpress.XtraReports.UI;
using DevExpress.XtraPrinting;
private void Report_AfterPrint(object sender, EventArgs e) {
// Cast sender to XtraReport to get access to the PrintingSystem and its pages.
XtraReport report = (XtraReport)sender;
// Iterate through all rendered pages.
foreach (DevExpress.XtraPrinting.Page page in report.PrintingSystem.Pages) {
// Get bricks generated by a specific XRControl (xrTable1).
var bricks = DevExpress.XtraPrinting.BrickSelector
.GetBricksByXRControl(page, xrTable1);
// Group bricks by vertical coordinate.
var lines = bricks.GroupBy(b => b.Rect.Y);
foreach (var line in lines) {
// Determine the maximum height within this line.
var height = line.Max(b => b.Size.Height);
foreach (var tableBrick in line)
foreach (var rowBrick in tableBrick.Bricks)
foreach (var cell in rowBrick.Bricks)
// Apply uniform height to each cell.
cell.Size = new System.Drawing.SizeF(
cell.Size.Width,
height
);
}
}
}
Imports DevExpress.XtraReports.UI
Imports DevExpress.XtraPrinting
Private Sub Report_AfterPrint(ByVal sender As Object, ByVal e As EventArgs)
' Cast sender to XtraReport to get access to the PrintingSystem and its pages.
Dim report As XtraReport = DirectCast(sender, XtraReport)
' Iterate through all rendered pages.
For Each page As DevExpress.XtraPrinting.Page In report.PrintingSystem.Pages
' Get bricks generated by a specific XRControl (xrTable1).
Dim bricks = DevExpress.XtraPrinting.BrickSelector.GetBricksByXRControl(page, xrTable1)
' Group bricks by vertical coordinate.
Dim lines = bricks.GroupBy(Function(b) b.Rect.Y)
For Each line In lines
' Determine the maximum height within this line.
Dim height = line.Max(Function(b) b.Size.Height)
For Each tableBrick In line
For Each rowBrick In tableBrick.Bricks
For Each cell In rowBrick.Bricks
' Apply uniform height to each cell.
cell.Size = New System.Drawing.SizeF(cell.Size.Width, height)
Next cell
Next rowBrick
Next tableBrick
Next line
Next page
End Sub
Hide or show elements depending on whether the current page is the first or last page of a group, based on tags stored in bricks.
private void XtraReport1_AfterPrint(object sender, EventArgs e) {
// Detect first page of each group.
string prevGroup = string.Empty;
for (int i = 0; i < Pages.Count; i++) {
DevExpress.XtraPrinting.Page page = Pages[i];
// Get the brick generated by xrLine1 on this page.
var line1 = System.Linq.Enumerable.FirstOrDefault(
DevExpress.XtraPrinting.BrickSelector
.GetBricksByXRControl(page, xrLine1)
);
if (line1 == null)
continue;
// Extract group key from Tag.
string currGroup = line1.Tag?.ToString() ?? string.Empty;
// Show only if this is the first page of the group.
line1.IsVisible = currGroup != prevGroup;
prevGroup = currGroup;
}
// Detect last page of each group.
string nextGroup = string.Empty;
for (int i = Pages.Count - 1; i >= 0; i--) {
DevExpress.XtraPrinting.Page page = Pages[i];
var line2 = System.Linq.Enumerable.FirstOrDefault(
DevExpress.XtraPrinting.BrickSelector
.GetBricksByXRControl(page, xrLine2)
);
if (line2 == null)
continue;
string currGroup = line2.Tag?.ToString() ?? string.Empty;
// Show only if this is the last page of the group.
line2.IsVisible = currGroup != nextGroup;
nextGroup = currGroup;
}
}
Private Sub XtraReport1_AfterPrint(ByVal sender As Object, ByVal e As EventArgs)
' Detect first page of each group.
Dim prevGroup As String = String.Empty
For i As Integer = 0 To Pages.Count - 1
Dim page As DevExpress.XtraPrinting.Page = Pages(i)
' Get the brick generated by xrLine1 on this page.
Dim line1 = System.Linq.Enumerable.FirstOrDefault(DevExpress.XtraPrinting.BrickSelector.GetBricksByXRControl(page, xrLine1))
If line1 Is Nothing Then
Continue For
End If
' Extract group key from Tag.
Dim currGroup As String = If(line1.Tag?.ToString(), String.Empty)
' Show only if this is the first page of the group.
line1.IsVisible = currGroup <> prevGroup
prevGroup = currGroup
Next i
' Detect last page of each group.
Dim nextGroup As String = String.Empty
For i As Integer = Pages.Count - 1 To 0 Step -1
Dim page As DevExpress.XtraPrinting.Page = Pages(i)
Dim line2 = System.Linq.Enumerable.FirstOrDefault(DevExpress.XtraPrinting.BrickSelector.GetBricksByXRControl(page, xrLine2))
If line2 Is Nothing Then
Continue For
End If
Dim currGroup As String = If(line2.Tag?.ToString(), String.Empty)
' Show only if this is the last page of the group.
line2.IsVisible = currGroup <> nextGroup
nextGroup = currGroup
Next i
End Sub
Generate clickable links in a document by pairing link bricks with target bricks and updating page numbers dynamically (custom table of contents).
View Example: Reporting for WinForms - Custom Table of Contents
using DevExpress.XtraReports.UI;
using DevExpress.XtraPrinting;
using System.Collections.Generic;
private static void CreateLinks(XtraReport report) {
// Prepare collections for link, target and page-number bricks.
List<DevExpress.XtraPrinting.VisualBrick> linkBricks = new();
List<DevExpress.XtraPrinting.VisualBrick> pageBricks = new();
List<TargetBrick> targetBricks = new();
// Enumerate all pages and all bricks.
foreach (DevExpress.XtraPrinting.Page page in report.Pages) {
foreach (DevExpress.XtraPrinting.VisualBrick brick in
DevExpress.XtraPrinting.BrickSelector.GetBricks(page)) {
if (brick.Tag == null)
continue;
string tagString = brick.Tag.ToString();
// Separate bricks by tag prefix.
if (tagString.StartsWith("Link_"))
linkBricks.Add(brick);
if (tagString.StartsWith("Target_"))
targetBricks.Add(new TargetBrick { Brick = brick, Page = page });
if (tagString.StartsWith("PageBrick_"))
pageBricks.Add(brick);
}
}
// Pair link bricks with their target bricks.
foreach (DevExpress.XtraPrinting.VisualBrick link in linkBricks) {
string key = link.Tag.ToString().Substring(5);
TargetBrick target = targetBricks.Find(
t => (string)t.Brick.Tag == string.Concat("Target_", key)
);
if (target == null)
continue;
// Configure navigation.
target.Brick.AnchorName = key;
link.Url = key;
link.NavigationPair =
DevExpress.XtraPrinting.BrickPagePair.Create(
target.Brick,
target.Page
);
// Update page number placeholder.
DevExpress.XtraPrinting.VisualBrick pageBrick =
pageBricks.Find(
b => (string)b.Tag == string.Concat("PageBrick_", key)
);
if (pageBrick != null)
pageBrick.Text = (target.Page.Index + 1).ToString();
}
}
private class TargetBrick {
public DevExpress.XtraPrinting.VisualBrick Brick { get; set; }
public DevExpress.XtraPrinting.Page Page { get; set; }
}
Imports DevExpress.XtraReports.UI
Imports DevExpress.XtraPrinting
Imports System.Collections.Generic
Private Shared Sub CreateLinks(ByVal report As XtraReport)
' Prepare collections for link, target and page-number bricks.
Dim linkBricks As New List(Of DevExpress.XtraPrinting.VisualBrick)()
Dim pageBricks As New List(Of DevExpress.XtraPrinting.VisualBrick)()
Dim targetBricks As New List(Of TargetBrick)()
' Enumerate all pages and all bricks.
For Each page As DevExpress.XtraPrinting.Page In report.Pages
For Each brick As DevExpress.XtraPrinting.VisualBrick In DevExpress.XtraPrinting.BrickSelector.GetBricks(page)
If brick.Tag Is Nothing Then
Continue For
End If
Dim tagString As String = brick.Tag.ToString()
' Separate bricks by tag prefix.
If tagString.StartsWith("Link_") Then
linkBricks.Add(brick)
End If
If tagString.StartsWith("Target_") Then
targetBricks.Add(New TargetBrick With {
.Brick = brick,
.Page = page
})
End If
If tagString.StartsWith("PageBrick_") Then
pageBricks.Add(brick)
End If
Next brick
Next page
' Pair link bricks with their target bricks.
For Each link As DevExpress.XtraPrinting.VisualBrick In linkBricks
Dim key As String = link.Tag.ToString().Substring(5)
Dim target As TargetBrick = targetBricks.Find(Function(t) CStr(t.Brick.Tag) = String.Concat("Target_", key))
If target Is Nothing Then
Continue For
End If
' Configure navigation.
target.Brick.AnchorName = key
link.Url = key
link.NavigationPair = DevExpress.XtraPrinting.BrickPagePair.Create(target.Brick, target.Page)
' Update page number placeholder.
Dim pageBrick As DevExpress.XtraPrinting.VisualBrick = pageBricks.Find(Function(b) CStr(b.Tag) = String.Concat("PageBrick_", key))
If pageBrick IsNot Nothing Then
pageBrick.Text = (target.Page.Index + 1).ToString()
End If
Next link
End Sub
Private Class TargetBrick
Public Property Brick As DevExpress.XtraPrinting.VisualBrick
Public Property Page As DevExpress.XtraPrinting.Page
End Class
The following code hides report elements in a document whose predecessors in a report (report controls) are tagged with the XRControl.Tag property set to “hide this”:
void Report_AfterPrint(object sender, EventArgs e) {
XtraReport report = (XtraReport)sender;
DevExpress.XtraPrinting.VisualBrick brick;
brick = BrickSelector.GetBricksByTag(report.PrintingSystem.Document.Pages[0], "hide this").FirstOrDefault();
brick.IsVisible = false;
}
Private Sub Report_AfterPrint(ByVal sender As Object, ByVal e As EventArgs)
Dim report As XtraReport = DirectCast(sender, XtraReport)
Dim brick As DevExpress.XtraPrinting.VisualBrick
brick = BrickSelector.GetBricksByTag(report.PrintingSystem.Document.Pages(0), "hide this").FirstOrDefault()
brick.IsVisible = False
End Sub