ProConcepts Reports - kataya/arcgis-pro-sdk GitHub Wiki
The Reports functionality in ArcGIS Pro is delivered through the ArcGIS.Desktop.Reports namespace in the ArcGIS.Desktop.Layouts assembly. This assembly provides classes and members that support managing reports, report elements and working with the report views. This includes creating new reports and report elements, modifying existing elements, managing selections, and report view control and navigation.
- ArcGIS.Desktop.Reports namespace in the ArcGIS.Desktop.Layouts.dll
Language: C#
Subject: Reports
Contributor: ArcGIS Pro SDK Team <[email protected]>
Organization: Esri, http://www.esri.com
Date: 11/24/2020
ArcGIS Pro: 2.7
Visual Studio: 2017, 2019
- Report class
- Reference an existing report
- Create a new report
- Report Sections
- Report View class
- Export a report
- Related reports
- Supplemental pages
- A complete, working example
The Report class provides access to basic report properties, report elements, and export methods. Reports are stored within projects as report items (visible in the Catalog pane) and a project can contain many reports. Existing reports appear in the Catalog pane as individual project items, or as open (report) views. There can be multiple views open for a single report, though, same as with all other view types, only one report view can be active at any one time.
There are a two ways to reference an existing report in a project: First, reference a report associated with an active report view, assuming there is one open and active in the application. The report is accessible off the ReportView's Report property (eg ReportView.Active.Report
). If there is no active report view then "ReportView.Active" will be null.
//Reference a report associated with an active report view
ReportView activeReportView = ReportView.Active;
if (activeReportView != null)
{
Report report = activeReportView.Report;
}
Second, reports can be accessed via their associated ReportProjectItem, located in the Catalog pane. Use ReportProjectItem.GetReport to return the underlying Report. To activate the report (i.e. open a report view), call ProApp.Panes.CreateReportPaneAsync(report);
. This is also covered in the Activate a Report View sub-section.
//Reference a report associated with a report project item
var reportItem = Project.Current.GetItems<ReportProjectItem>()
.FirstOrDefault(item => item.Name.Equals("Some Report Name"));
if (reportItem != null)
{
//Get the report associated with the reportItem
Report report = await QueuedTask.Run(() => reportItem.GetReport());
//activate a view
FrameworkApplication.Panes.CreateReportPaneAsync(report);//Must be called on the UI
}
Reports are created programmatically via the various ReportFactory.Instance.CreateReport method overloads. When a report is created a report project item is added to the Contents pane but it is not automatically opened in a new report view. Call FrameworkApplication.Panes.CreateReportPaneAsync(report)
to activate a new report view, as needed. FrameworkApplication.Panes.CreateReportPaneAsync must be called on the UI thread.
To create a new report with minimum parameters, use the overload that accepts a report name (string) and the ReportDataSource. Use the ReportDataSource class to define properties such as the fields to be displayed in the report as well as a definition query that filters the underlying data. This is described in further detail in the Report Datasource section:
//Create a new report using minimum properties
QueuedTask.Run(() =>
{
var newReport = ReportFactory.Instance.CreateReport("New Report", reportDataSource);
//TODO use the report
});
You can also create a report with more advanced options by using a specific Report Template, styling options, field statistics, page size and margins. Detailed help on how to work with ReportTemplate, Report Styling and Report Page configurations are provided in the following sections.
public Report CreateReport(
string name,
ReportDataSource reportDataSource,
CIMPage page,
IEnumerable<ReportFieldStatistic> statistics,
ReportTemplate template,
string styling
)
Refer to the Sorting and Grouping data section on how to sort and group report fields. You can also generate summary statistics for a report as well.
A Report is generated as a well-formatted, multipage representation of your data. The ReportDataSource class represents the data source for a report. Use the Report.DataSource property to access its ReportDataSource.
var reportProjItem = Project.Current.GetItems<ReportProjectItem>().First(item => item.Name.Equals("USAReports"));
Report report = reportProjItem.GetReport();
ReportDataSource dataSource = report.DataSource;
To create a ReportDatasource, use one of two available constructors. The first constructor requires: a MapMember, an optional string definition query for features selection in the MapMember (pass an empty string if there is no definition query), a boolean that specifies if the existing selection (on the map member) should be used, and a collection of CIMReportFields to include in the Report. The map member should point to either a standalone table or a feature layer.
//Get the MapMember whose datasource you want to use for the report
var featureLayerToUse = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>()
.FirstOrDefault(f => f.Name == "NewCities");
if (featureLayerToUse == null) return;
var listOfFields = new List<CIMReportField>
{
new CIMReportField{Name = "STATE_NAME"},
new CIMReportField{Name = "CITY_NAME"},
new CIMReportField{Name = "ELEVATION"}
};
//Create the ReportDatasource using the MapMember, list of fields...
var reportDataSource = new ReportDataSource(featureLayerToUse, "", false, listOfFields);
The second constructor is similar, but takes a CIMDataConnection instead of a standalone table or feature layer map member. In this example, a CIMDataConnection is defined for a feature class "NewCities" within a local file geodatabase "TestingReports.gdb".
//Get the file geodatabase
Geodatabase geodatabase = new Geodatabase(
new FileGeodatabaseConnectionPath(new Uri(@"C:\Path\TestingReports.gdb")));
//Build the CIMDataConnection
CIMStandardDataConnection cimDataConnection = new CIMStandardDataConnection
{
WorkspaceConnectionString = geodatabase.GetConnectionString(),
WorkspaceFactory = WorkspaceFactory.FileGDB,
Dataset = "NewCities",
DatasetType = esriDatasetType.esriDTFeatureClass
};
//Define fields to use for the ReportDataSource
var listOfFields = new List<CIMReportField> {
new CIMReportField{Name = "STATE_NAME"},
new CIMReportField{Name = "CITY_NAME"},
new CIMReportField{Name = "ELEVATION"}
};
//Create the ReportDataSource using the CIMDataConnection
var reportDataSource = new ReportDataSource(cimDataConnection, "", false, listOfFields);
Once the ReportDataSource is constructed, call ReportFactory.Instance.CreateReport to generate the new Report:
//Create the ReportDataSource using the CIMDataConnection or MapMember
ReportDataSource reportDataSource = new ReportDataSource(cimDataConnection, "", false, listOfFields);
//Create a report
ReportFactory.Instance.CreateReport(reportName, reportDataSource);
Use the Report.SetDataSource to apply changes to the underlying report data source:
//On the QueuedTask
//Get the MapMember whose datasource you want to use for the report
var featureLayerToUse = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().
FirstOrDefault(f => f.Name == "NewCities");
if (featureLayerToUse == null) return;
//Get the report whose datasource will be changed
var reportProjItem = Project.Current.GetItems<ReportProjectItem>().
First(item => item.Name.Equals("USAReports"));
var report = reportProjItem.GetReport();
var listOfFields = new List<CIMReportField>
{
new CIMReportField{Name = "STATE_NAME"},
new CIMReportField{Name = "CITY_NAME"},
new CIMReportField{Name = "ELEVATION"}
};
//Create the ReportDatasource using the MapMember, list of fields...
ReportDataSource rdsrc = new ReportDataSource(featureLayerToUse, "", false, listOfFields);
//Update the report's datasource
report.SetDataSource(rdsrc);
Sorting organizes report records in alphabetical or numerical order based on the values in one or more fields. Grouping gathers together report records using a common value. Sorting and Grouping information is configured on each individual CIMReportField added to the CIMReportField collection. Use the CIMReportField.SortInfo and CIMReportField .SortOrder properties
The collection is either passed to a ReportDataSource when it is being created or applied to an existing report via Report.SetDataSourceFields:
//Must be on the QueuedTask
//Collection of fields where the CITY_NAME field is sorted in Ascending order
var listOfFields = new List<CIMReportField>
{
new CIMReportField{Name = "STATE_NAME"},
new CIMReportField{Name = "CITY_NAME", SortOrder = 1, SortInfo = FieldSortInfo.Asc},
new CIMReportField{Name = "ELEVATION"}
};
//To sort, either
//Create a ReportDatasource and create a report
var reportDatasource = new ReportDataSource(featureLayerToUse, "", false, listOfFields);
ReportFactory.Instance.CreateReport("report name", reportDatasource);
//Or, apply the sorting to an existing report via SetDataSourceFields
var existingReport = ...;
existingReport.SetDataSourceFields(listOfFields);
Grouping is defined similarly. Report data can be grouped on a common (repeating) value within the given field and is specified via the CIMReportField.Group property. For example, this snippet is grouping a list of cities together based on which State they are in. As before, provide the list of CIMReportFields either as the parameter to a ReportDataSource when creating it or to an existing report via its SetDataSourceFields method:
var listOfFields = new List<CIMReportField>
{
new CIMReportField{Name = "STATE_NAME", Group = true}, //group on common state names
new CIMReportField{Name = "CITY_NAME", SortOrder = 1, SortInfo = FieldSortInfo.Asc},
new CIMReportField{Name = "ELEVATION"}
};
//To group, either
//Create a ReportDatasource and create a report
var reportDatasource = new ReportDataSource(featureLayerToUse, "", false, listOfFields);
ReportFactory.Instance.CreateReport("report name", reportDatasource);
//Or, apply the sorting to an existing report via SetDataSourceFields
var existingReport = ...;
existingReport.SetDataSourceFields(listOfFields);
Note: when a field is grouped, it is automatically sorted.
Fields on an existing report can also be grouped via the Report.AddGroup method. Grouping can be removed via Report.RemoveGroups passing in a list of one or more field names for which grouping will be removed. An overload of RemoveGroups allows you to specify a/the ReportSection(s) containing the group(s):
//On the QueuedTask
//Add a Group.
existingReport.AddGroup("STATE_NAME", true, true, "");
//Remove a group
existingReport.RemoveGroups(new List<string> { "STATE_NAME" });
Predefined field placement and text color can be used to define the initial layout of the report upon creation without the need to alter each element individually. ReportTemplates, Report styling, page size, page orientation, and margin space options are available during report creation to expedite the report creation process. Summary statistics can also be defined.
Use the ReportTemplateManager class to dictate the location of elements within a report. ReportTemplateManager is a static class that allows you to access five pre-determined ReportTemplates available for use with Pro. Use the GetTemplates method, or its asynchronous equivalent GetTemplatesAsync, to access them. Any one of these ReportTemplate choices can be passed as a parameter to ReportFactory.Instance.CreateReport.
The five templates available with Pro are:
- Attribute List: Generates a list of rows, with columns for the chosen attributes. This is the default if no grouping is defined.
- Attribute List with Grouping: Generates a list of rows, with columns for the chosen attributes, grouped by a unique field. This is the default if grouping is defined.
- Basic Summary: Generates a list of the specified summary statistics. No individual rows are listed.
- Basic Summary with Grouping: Generates a list of the specified summary statistics, grouped by a unique field. No individual rows are listed.
- Page Per Feature: Generates a separate page for each feature, listing the chosen attributes.
//Create report using the "Attribute List" ReportTemplate option.
var reportTemplate = ReportTemplateManager.GetTemplates().FirstOrDefault(rt => rt.Name == "Attribute List");
ReportFactory.Instance.CreateReport(
ReportName, reportDataSource, reportCIMPage, reportFieldStats, reportTemplate, "Warm Tones");
With the Reports SDK, it is possible to designate the appearance properties of elements with one of four style options. Any one of these style options can be passed as a "string" to ReportFactory.Instance.CreateReport. The ReportStylingManager static class provides a GetStylings and a GetStylingsAsync method to access Pro's pre-determined styles. These are the four literal strings to use for the pre-determined styles:
- No Styling
- Black and White
- Cool Tones
- Warm Tones
//Creates a report with the "Warm Tones" styling option.
ReportFactory.Instance.CreateReport(
ReportName, reportDataSource, reportCIMPage, reportFieldStats, reportTemplate, "Warm Tones");
You can modify the report page's height, width, units, or margins using the CIMPage class. Pass in the configured CIMPage object as a parameter to ReportFactory.Instance.CreateReport:
//Create report using a custom CIMPage configuration.
var reportCIMPage = new CIMPage
{
Units = LinearUnit.Inches,
Height = 11,
Width = 8.5,
Margin = new CIMMargin { Bottom = 1, Top = 1, Left = .5, Right = .5},
};
ReportFactory.Instance.CreateReport(ReportName, reportDataSource, reportCIMPage, reportFieldStats,
reportTemplate, "Black and White");
Summary Statistics that you can include in the report are:
- Count: The count of all field values.
- Minimum: The maximum field value.
- Maximum: The minimum field value.
- Range: The difference between the maximum and minimum field values.
- Sum: The sum of all field values.
- Mean: The average of all field values.
- Median: The middle value of all field values.
- Mode: The most common value of all field values.
- StandardDeviation: The standard deviation of the field values.
ReportFactory.Instance.CreateReport method provides an overload for including summary statistics in your report. By default, summary statistics will be added to a ReportFooter or ReportGroupFooter section (depending on whether the summary statistics are being computed on a field that is grouped or not).
public Report CreateReport(
string name,
ReportDataSource reportDataSource,
CIMPage page,
IEnumerable<ReportFieldStatistic> statistics,
ReportTemplate template,
string styling
)
The IEnumerable<ReportFieldStatistic> parameter controls the statistic to generate for a given field. For each field that you need to generate a summary statistic for, a corresponding ReportFieldStatistic item must be provided in the ReportFieldStatistic collection parameter. Use ReportFieldStatistic.Field to define the field name and ReportFieldStatistic.Statistic to define the type of summary statistic to display. Statistic an enum is of type FieldStatisticsFlag.
In the code snippet below, a summary statistic is being generated for the POP2000 field in a report on USA state information.
//Report field statistics
List<ReportFieldStatistic> reportFieldStats = new List<ReportFieldStatistic>{
//Generate the total (sum) population statistics for the state in 2000
new ReportFieldStatistic{ Field = "POP2000", Statistic = FieldStatisticsFlag.Sum }
};
//Set ReportDatasource object, style etc....
//Create report using the collection of ReportFieldStatistic
ReportFactory.Instance.CreateReport(ReportName, reportDataSource, null, reportFieldStats,
reportTemplate, SelectedReportStyle);
To add summary statistics for a field to an existing report, use ReportElementFactory.Instance.CreateFieldStatisticTextElement. The parameters required for this method are:
- A ReportFooter section of the report (see next section on report sections)
- An envelope geometry that specifies the location at which to place statistic element on the report view
- A ReportFieldStatistic object that defines the field and statistics info needed
- A text symbol to be used to display the information on the report.
var newReportFieldStatistics = new ReportFieldStatistic
{
Field = "POP1990",
Statistic = FieldStatisticsFlag.Maximum
};
//Get the ReportFooter
var mainReportSection = report.Elements.OfType<ReportSectionElement>().FirstOrDefault();
var reportFooter = mainReportSection1?.Elements.OfType<ReportFooter>().FirstOrDefault();
//Create field statistics
var ge = ReportElementFactory.Instance.CreateFieldStatisticTextElement(reportFooter,
newFieldEnvelope, newReportFieldStatistics, textSymbol);
Each report is divided into sections to support arranging content in a consistent fashion. All reports contain a main ReportSection which can be accessed via the Report.Elements property. Retrieve the first element of type "ReportSection":
//Either
ReportSection mainReportSection = report.Elements.FirstOrDefault() as ReportSection;
//or
ReportSection mainReportSection = report.Elements.OfType<ReportSection>().FirstOrDefault();
The ReportSection contains a collection of child sections including:
These five sections are available in the ReportSection by default. The ReportDetails section is where the attribute contents will be displayed.
If the report is grouped on an attribute, the following two sections also exist in the report:
Summary statistics for a report are added to either the ReportFooter or the ReportGroupFooter sections. See Sorting and Grouping data for how to group fields in a report and Summary Statistics for how to apply summary statistics.
//Get the "ReportSectionElement"
//ReportSectionElement contains the ReportHeader, ReportPageHeader, ReportDetails,
//ReportPageFooter, ReportFooter sections.
var mainReportSection = report.Elements.OfType<ReportSectionElement>().FirstOrDefault();
//Get the ReportHeader
var reportHeader = mainReportSection?.Elements.OfType<ReportHeader>().FirstOrDefault();
//Get the ReportHeader
var reportPageHeader = mainReportSection?.Elements.OfType<ReportPageHeader>().FirstOrDefault();
//Get the "ReportDetails" within the ReportSectionElement. ReportDetails is where "fields" are.
var reportDetailsSection = mainReportSection?.Elements.OfType<ReportDetails>().FirstOrDefault();
//Get the ReportPageFooter
var reportPageFooter = mainReportSection?.Elements.OfType<ReportPageFooter>().FirstOrDefault();
//Get the ReportFooter
var reportFooter = mainReportSection?.Elements.OfType<ReportFooter>().FirstOrDefault();
After obtaining a reference to a report, it can be modified by adding new content elements such as fields and statistics. It is important to understand the structure of a report and the report sections so that content elements can be added to the appropriate section(s). Report elements can be static (such as title or column header text) or dynamic (such as field values and statistics, chart frames, dynamic pictures, or attachments). Dynamic elements update with each report record or groups of records.
Elements are created via the ReportElementFactory (a singleton). The elementContainer parameter on the various ReportElementFactory methods identifies the section within which a particular element will be created. In all cases, when constructing an element, an Envelope that specifies the location of the element on the report must be provided. The ReportElementFactory.Instance provides the following methods for element creation:
- CreateAttachmentFrame: Creates an attachment frame element on a report from an envelope geometry. If the report data source contains attachments, add an AttachmentFrame to the ReportDetails section. Attachments are stored at the database level.
- CreateChartFrame: Creates a chartFrame element on a report from an envelope geometry. If the report data source is a map member and a chart frame already exists for the layer, insert a ChartFrame into the Group Header, Group Footer, Report Header, or Report Footer.
- CreateDynamicPictureGraphicElement: Creates a dynamic picture element on a report from an envelope geometry.
- CreateFieldStatisticTextElement : Creates a field statistic dynamic text element on a report from an envelope geometry. Field statistics are added to summarize report records (Sum, Mean, Maximum, Count, etc) in the Group or Report Footer section.
- CreateFieldValueTextElement: Creates a field value dynamic text element on a report from an envelope geometry. Field values are added to the Group Header, Group Footer, or Details section.
- CreateRectangleParagraphGraphicElement: Creates a graphic rectangle text element on a layout from an envelope geometry. This method allows you to create static text elements to any section of a report. The value does not change as the report records change. In this example, a field will be added to the ReportDetails section:
//Must be on QueuedTask
//Creates a new field value text element within the ReportDetails section of a report.
//Field to add
var newReportField = new CIMReportField
{
Name = "POP1990",
};
//Create a field element in the ReportDetails section
//Get the "ReportSectionElement"
var mainReportSection = report.Elements.OfType<ReportSectionElement>().FirstOrDefault();
if (mainReportSection == null) return;
//Get the "ReportDetails" within the ReportSectionElement. ReportDetails is where "fields" are.
var reportDetailsSection = mainReportSection?.Elements.OfType<ReportDetails>().FirstOrDefault();
if (reportDetailsSection == null) return;
Envelope newFieldEnvelope = EnvelopeBuilder.CreateEnvelope(newMinPoint, newMaxPoint);
//Create field
var fieldGraphic = ReportElementFactory.Instance.CreateFieldValueTextElement(
reportDetailsSection, newFieldEnvelope, newReportField);
All report elements are contained in a ReportSection. To select elements in the report, access the ReportSection that contains the element and use the following methods to manipulate its element selection:
- ClearElementSelection
- GetSelectedElements
- SelectAllElements
- SelectElements
- GetElementsAsFlattenedList.
When either getting or setting the selection, a collection of one or more elements is used.
if (ReportView.Active == null)
return;
var report = ReportView.Active.Report;
// Find a field graphic in the ReportDetails section and zoom to it.
//Get the "ReportSectionElement"
var mainReportSection = report.Elements.OfType<ReportSectionElement>().FirstOrDefault();
if (mainReportSection == null) return;
//Get the "ReportDetails" within the ReportSectionElement. ReportDetails is where "fields" are.
var reportDetailsSection = mainReportSection?.Elements.OfType<ReportDetails>().FirstOrDefault();
if (reportDetailsSection == null) return;
var elements = reportDetailsSection.GetElementsAsFlattenedList();
reportDetailsSection.SelectElements(elements);
//Zoom to selection
await QueuedTask.Run(() => reportView.ZoomToSelectedElements());
Report views are the primary interface used to display, navigate, select, and edit report elements in the report. The report being visualized in the view is accessed via the view's Report property (e.g. ReportView.Active.Report
). Note that:
- Multiple report views can reference the same report.
- A report view may be open but may not be active.
- The active view is not necessarily a report view.
Assuming a report view is open, but not active, iterate through the pane collection on the FrameWorkApplication class, isolate the report pane of interest, and then active it. To open a new view (either for an existing report or a newly created report) call FrameWorkApplication.Panes.CreateReportPaneAsync method. Pane activation must be called on the UI thread:
//Assume we want to open a view for a particular report or activate a view if one
//is already open
ReportProjectItem reportItem = Project.Current.GetItems<ReportProjectItem>()
.FirstOrDefault(item => item.Name.Equals("some report"));
if (reportItem != null)
{
Report report = await QueuedTask.Run(() => reportItem.GetReport());
//Next check to see if a report view is already open that references the report
foreach (var pane in ProApp.Panes)
{
var reportPane = pane as IReportPane;
//if not a report view, continue to the next pane
if (reportPane == null) //if not a report view, continue to the next pane
continue;
//if there is a match, activate the view
if (reportPane.ReportView.Report == report)
{
(reportPane as Pane).Activate();//Must be called on the UI
return;
}
}
//No pane found, activate a new one
ProApp.Panes.CreateReportPaneAsync(report);
}
To export a report to a pdf format, use Report.ExportToPDF. This method requires four parameters:
- The name of the output pdf file.
- PDFFormat to specify the options for the generated PDF (including full path).
- ReportExportOptions to define export options such as page numbering (see below).
- A boolean parameter to specifying whether to use the current selected set of features.
//On QueuedTask
//var report = ...;
//Create PDF format with appropriate settings
var pdfFormat = new PDFFormat() {
Resolution = 300;
OutputFileName = Path.Combine(Project.Current.HomeFolderPath, report.Name)
};
//Define Export Options
var exportOptions = new ReportExportOptions {
ExportPageOption = ExportPageOptions.ExportAllPages,
TotalPageNumberOverride = 12,
StartingPageNumberLabelOffset = 0
};
var useSelection = true;
report.ExportToPDF(report.Name, pdfFormat, reportExportOptions, useSelection);
ReportExportOptions has the following options:
- StartingPageNumberLabelOffset property allows you to customize the starting page number of the exported pages. The reason to customize the starting page number would be if the report PDF is going to be included in a larger report. For instance, if you needed to include a 3 page introduction to your report, the property would be set to 4. The first page of the exported report would start with a page number of 4 instead of 1.
- TotalPageNumberOverride property will specify the total page number for the report, taking into account the other pages in your larger report.
- ExportPageOption property allows you to specify the collection of report pages to be exported. Use the ExportPageOptions Enumeration to set the collection type.
ExportPageOptions | Description |
---|---|
ExportAllPages | Export all pages. |
ExportByPageRange | Export a custom page range. |
ExportEvenPagesOnly | Export even pages only. |
ExportLastPage | Export the last page only. |
ExportOddPagesOnly | Export odd pages only. |
ExportSelectedIndexFeatures | Export the selected index features. |
ExportSelectedPage | Export the selected page. |
ExportSelectedTOCPages | Export the selected TOC pages. |
- CustomPages property is used in-conjunction with ExportPageOption = ExportPageOptions.ExportByPageRange. Use a hypen "-" to delimit a page range and a comma-delimited list to include multiple pages. The two can be combined. For example, "1-3" would export pages 1-3. The value "1-3,5,9-11" would export pages 1-3, 5, and 9-11.
Data sources with defined relates or relationship classes can be added to show additional information about your main report. A report can have multiple related reports. For example, assuming a report about US states, there could be related reports for US counties and US cities included as well. The Report.AddRelatedReport method supports adding a related report. Adding a related report is similar to creating a report, with parameters for the related report data source, field properties, template, and styling.
public void AddRelatedReport(
string relateName,
string relateTitle,
string insertSectionName,
CIMReportDataSource reportDataSource,
CIMReportElementFieldProperties[] statProperties,
string templatePath,
string styling
)
Supplemental pages provide additional information for the report including a table of contents, an acknowledgment and credits page, or a map. Supplemental pages are Layout views which must already exist in the project. Use Report.AddLayoutPage to insert a supplemental page below the main report section.
Note: Supplemental pages are represented as report sections. When these pages are added to a report, the view updates to show a Report Document view. This view shows a list of all report sections. Unlike the main report, supplemental page sections can be moved. Report.MoveReportSectionElement will move these sections to a new location in the report document.
Supplemental pages are also by-ref. Any updates made to the underlying layouts will be reflected in the final PDF export.
A complete working example of creating a report from a data source and then modifying it to include new attribute fields is provided in this sample: CreateReport