Skip to content

Subreports

Peter Gill edited this page Jun 7, 2026 · 1 revision

Sub-reports

A sub-report embeds one report inside another. The outer (parent) report defines the layout and data; the inner (child) report is a separate .rdl file that the engine loads and renders inline.

Creating a sub-report in the designer

  1. Open the parent report in the designer.
  2. From the toolbox, drag a Subreport item onto the report body.
  3. Right-click the sub-report item and choose Properties.
  4. In the Report Name field, enter the path to the child .rdl file — either an absolute path or a path relative to the parent report's folder.
  5. Optionally map parameters from the parent report to the child using the Parameters tab.

How the engine locates the child report

The engine resolves the child .rdl path relative to the Folder property set on RDLParser. Always set Folder when parsing a report that contains sub-reports.

var rdlp = new RDLParser(await System.IO.File.ReadAllTextAsync(rdlPath))
{
    Folder = Path.GetDirectoryName(rdlPath)
};
using var report = await rdlp.Parse();

Supplying data to a sub-report from code

When the child report uses a live database query, no extra code is needed — the engine runs the child's query automatically.

When the child report's dataset should be populated from a DataTable (instead of a database query), subscribe to the SubreportDataRetrieval event on the parent Report before calling RunGetData. The event fires once per sub-report instance, passing a SubreportDataRetrievalEventArgs whose Report property is the child report.

using Majorsilence.Reporting.Rdl;

RdlEngineConfig.RdlEngineConfigInit();

var rdlp = new RDLParser(await System.IO.File.ReadAllTextAsync(rdlPath))
{
    Folder = Path.GetDirectoryName(rdlPath)
};
using var report = await rdlp.Parse();

// Subscribe before RunGetData
report.SubreportDataRetrieval += (sender, e) =>
{
    // e.Report is the child Report instance
    // Supply data to the child's DataSet
    var childDataTable = GetChildData();   // your method
    e.Report.DataSets["ChildDataSetName"].SetData(childDataTable);
};

await report.RunGetData(null);

using var ms = new MemoryStreamGen();
await report.RunRender(ms, OutputPresentationType.PDF);
var pdf = ((System.IO.MemoryStream)ms.GetStream()).ToArray();

Sub-reports in the viewers

The Avalonia and WinForms viewers expose the same event via their own surface so you can wire it up without accessing the Report object directly.

Avalonia viewer

ReportViewer.SubreportDataRetrieval += (sender, e) =>
{
    e.Report.DataSets["ChildDataSetName"].SetData(GetChildData());
};
await ReportViewer.SetSourceFileAsync(new Uri(rdlPath));

WinForms viewer

// Wire up after SetSourceFile, before Rebuild
var rpt = await rdlView.Report();
rpt.SubreportDataRetrieval += (sender, e) =>
{
    e.Report.DataSets["ChildDataSetName"].SetData(GetChildData());
};
await rdlView.Rebuild();

Connection string override for sub-reports

To override the connection string in the child report as well as the parent, set OverwriteInSubreport = true on RDLParser:

var rdlp = new RDLParser(rdlSource)
{
    Folder = Path.GetDirectoryName(rdlPath),
    OverwriteConnectionString = "Server=prod;Database=mydb;Integrated Security=true",
    OverwriteInSubreport = true
};

Clone this wiki locally