Developers / Create Designer and Viewer Applications / End User Report Designer in WinForms Application / Use End-User Report Designer API / Work with a Report
Work with a Report

The End User Designer API for WinForms allows you to perform common operations with a report using the Designer class.

Initialize Designer with a new report

Use Designer.NewReport method to create a new empty report and initialize the Designer as shown in the code example.

C#. Add using statements on the top of Form.cs
Copy Code
using System.Windows.Forms;
using GrapeCity.ActiveReports.Design;
C# code. Paste INSIDE the Form Load event
Copy Code
var _designer = new Designer() { Dock = DockStyle.Fill };
_designer.NewReport(DesignerReportType.RdlMultiSection);
Controls.Add(_designer);

Note: You should use the Report property only if you want to get the current state information. Please do not use this property if you need to change the report state or assign a new report.

Initialize Designer with a specified report

Use the Designer.LoadReport method to initialize the Designer by loading a report created in code, as demonstrated in the code example.

Copy Code
var report = new PageReport {
      Report = {
        DataSources = {
              new DataSource {
                  Name = "MainDataSource",
                  ConnectionProperties = {
                      ConnectString = "<your_connection_string>",
                      DataProvider = "MSSQL",
                  }
              }
          }
      }
  };
//Serialize and load report into the designer
_designer.LoadReport(XmlReader.Create(new StringReader(report.ToRdlString())), DesignerReportType.Rdl);

Save a report

Save a report to any storage by passing the XmlWriter object to the Designer.SaveReport method. See the example code for details.

C#. Add using statements on the top of Form.cs
Copy Code
using System.IO;
using System.Xml;
using GrapeCity.ActiveReports.Design;
C#.
Copy Code
private void SaveReport(Stream outStream)
{
  using(var writer = XmlWriter.Create(outStream))
  {
    _designer.SaveReport(writer);
  }
}

Define a font resolver

Using the Designer.FontResolver property, you can provide your own fonts to be used for the report design and preview. For that, you must first define your own font resolver and then attach it to the Designer instance. See the code example for details.

C#. Add using statements on the top of Form.cs
Copy Code
using GrapeCity.ActiveReports;
using GrapeCity.ActiveReports.Design;
C#. Define a custom font resolver
Copy Code
public sealed class DirectoryFontResolver : IFontResolver
{
    GrapeCity.Documents.Text.FontCollection _fonts;

    public DirectoryFontResolver(string fontsDirectory)
    {
        _fonts = new GrapeCity.Documents.Text.FontCollection();
        // load standard Windows fonts
        _fonts.RegisterDirectory(Environment.GetFolderPath(Environment.SpecialFolder.Fonts));
        // load fonts from custom directory
        _fonts.RegisterDirectory(fontsDirectory);
        _fonts.DefaultFont = _fonts.FindFamilyName("Arial");
    }
    GrapeCity.Documents.Text.FontCollection IFontResolver.GetFonts(string familyName, bool isBold, bool isItalic)
    {
        var fonts = new GrapeCity.Documents.Text.FontCollection();
        fonts.Add(_fonts.FindFamilyName(familyName, isBold, isItalic) ?? _fonts.DefaultFont);
        return fonts;
    }
}
C#. Attach a custom font resolver to the Designer instance
Copy Code
class MyDesignerForm : Form
{
  public MyDesignerForm()
  {
    InitializeComponent();
    //The designer must be added to the form with the name '_designer'.    
    _designer.FontResolver = new DirectoryFontResolver("c:\\Fonts");
  }
}

Specify a custom resource locator

Using the Designer.ResourceLocator property, you can define a custom resource locator to get the resources (like images, subreports) from the custom storage or at a specific disk location. First, define the custom resource locator and then use it in the Designer. See the code example for details.

C#. Add using statements on the top of Form.cs
Copy Code
using System;
using System.IO;
using System.Drawing;
using GrapeCity.ActiveReports;
C#. Define a custom resource locator
Copy Code
class MyResourceLocator : ResourceLocator
{
    public override Resource GetResource(ResourceInfo resourceInfo)
    {
        if (resourceInfo.Name == "redSquare.png")
        {
            //Here we draw the image with the red square in the center.
            //You can load the image from file system, or from data base, or from assembly resources.
            var img = new Bitmap(100, 100);
            var graphics = Graphics.FromImage(img);
            var redBrush = new SolidBrush(Color.Red);
            graphics.FillRectangle(redBrush, 10, 10, 80, 80);
            var tmpStream = new MemoryStream();
            img.Save(tmpStream, System.Drawing.Imaging.ImageFormat.Png);
            tmpStream.Position = 0;
            return new Resource(tmpStream, new Uri("redSquare.png", UriKind.Relative));
        }
        return new Resource();
    }
}
C#. Attach a custom resource locator to the Designer instance
Copy Code
class MyDesignerForm : Form
{
  public MyDesignerForm()
  {
    InitializeComponent();
    //The designer must be added to the form with the name '_designer'.   
    _designer.ResourceLocator = new MyResourceLocator();
  }

Execute specific Designer actions

With the Designer.ExecuteAction(DesignerAction) method, you can execute some specified designer action. Most Designer APIs related to reports are encapsulated into the ExecuteAction method. The code example below demonstrates how you can remove all selected items.

C#
Copy Code
private void RemoveSelectedItems()
{
  _designer.ExecuteAction(DesignerAction.EditDelete);
}

The code example below demonstrates how you can select all items and remove them.

C#
Copy Code
private void Clear()
{
  _designer.ExecuteAction(DesignerAction.SelectAll);
  _designer.ExecuteAction(DesignerAction.EditDelete);
}

Supply credentials for a data provider

Use the Designer.LocateCredentials event to provide credentials for data providers as demonstrated in the code example.

C#. Add using statements on the top of Form.cs
Copy Code
using System.Windows.Forms;
using GrapeCity.ActiveReports;
using GrapeCity.ActiveReports.Design;
C#
Copy Code
_designer.LocateCredentials += (sender, args) => {
  args.UserName = "sa";
  args.Password = "12345";
}

Provide data for a page report

Use the Designer.LocateDataSource event to provide data for previewing a page report as demonstrated in the code example.

C#
Copy Code
_designer.LocateDataSource += (sender, args) => {
  var dataSourceName = args.DataSet.Query.DataSourceName;
  var dataSource = ((PageReport)designer.Report).Report.DataSources.First(x => x.Name == dataSourceName);
  if(dataSource.ConnectionProperties.DataProvider == "OBJECT")
  {
    args.Data = new[] { new { CustomerName = "Gc Inc." } };
  }
};

Get the selected items collection

Use the Designer.Selection property or the Designer.SelectionChanged event to react to selection changes. Using the Designer.Selection property, you can get the selected items collection. The code example below demonstrates changing the 'remove' button state, which must be enabled only when there are selected items.

C#
Copy Code
_designer.SelectionChanged += () {
  removeButton.Enabled =
    _designer.Selection.OfType<ReportItem>().Count() > 0
    || designer.Selection.OfType<ARControl>().Count() > 0;
}

Get the changed undo history

The UndoManager.Changed event occurs when the report was changed and therefore the undo history was changed as well. You can use this event in the conjunction with the UndoManager.UndoCount and UndoManager.RedoCount properties to set the Undo/Redo buttons state as shown in the code example.

C#
Copy Code
_designer.UndoManager.Changed += (sender, e) => {
  _undoButton.Enabled = _designer.UndoManager.UndoCount > 0;
  _redoButton.Enabled = _designer.UndoManager.RedoCount > 0;
};

Handle actions after changing the report layout

With the Designer.LayoutChanged event, you can execute some actions right after the layout has been changed as in the code example below.

C#
Copy Code
_designer.LayoutChanged += (sender, args) => {
  //do some work here
};

Handle report layout changes

The Designer.LayoutChanging event allows to handle the report layout changes. The example below deprecates adding a new control without a dataset.

C#
Copy Code
_designer.LayoutChanging += (sender, args) => {
      if (args.Type == LayoutChangeType.ControlAdd
      && designer.Report is PageReport pageReport
      && pageReport.Report.DataSets.Count == 0)
      {
        ((IUIService)designer).ShowError("Add data set first.");
        args.AllowChange = false;
      }
  };

Check if a Designer action is enabled

With the Designer.QueryActionEnabled(DesignerAction) method, you can check if a specific action in the Designer is enabled.

C#
Copy Code
var canConvert = designer.QueryActionEnabled(DesignerAction.ConvertToMaster);
//canConvert value will be 'false' for master reports and 'true' for rdl reports.

Return a currently opened report

The Designer.Report property returns a currently opened report, which can be a Page report or a Section report.

To set a report, you should use the Designer.LoadReport method.
C#
Copy Code
var extension = switch designer.Report {
  PageReport => ".rdlx",
  SectionReport => ".rpx",
  _ => throw new Exception("Unknown report type.")
};

Update some button states after the report changes

The Designer.ReportChanged event occurs when any change to a report has been applied (layout changes or data layer changes). You can use this event to update some button states as in the example below.

C#
Copy Code
_designer.ReportChanged += (sender, args) => {
  saveButton.Enabled = true;
};

Show the Data Source creation wizard

The Designer.RunDataWizard event opens the data source creation wizard.

C#
Copy Code
private void RunDataWizardButtonClick(object sender, EventArgs e)
{
    _designer.RunDataWizard();
}