C# – Excel, Image, PDF Report with RDLC in Master/Details and MultiColumn

There is maybe a complicated definition of the word “report” in IT application but for me it’s pretty simple. A report is just an interface between what the user gives and what he wants to see. He may have many data sources which build up a same designed form of report or he has one data source and would like to display it in different ways. Because of this loosing relation there are a lot of Report components for .NET framework to fulfill programmer’s entire requirement. Some popular commercial ones are Crystal Report, List & Label, ComponentOne Reports, etc. … which provide flexible ways so that a user (without having any programming skills) can customize his report as he desires. Of course, a commercial one is always expensive because of his numerous abilities. However in some cases we don’t need such complicated reporting tool but only a simple one to illustrate data as predefined template. In this case we can use the Report Viewer (accompanied with .NET Framework) to create many kinds of basic reports. I know there are a lot of tutorials about RDLC (Report Viewer) in Internet, for examples at this site http://gotreportviewer.com/ but I would like to write another one. First it’s for myself to look up when I need (because I don’t regularly use Report Viewer component, I use List & Label at work) and second it maybe will help some newbies who need very basic tutorial about Report Viewer. If you are professional, you can just skip this post.

This blog post will discuss 3 supported types of Report Viewer (.RDLC): PDF, Excel and Image. For each type of report, I will insert some custom modifications to keep it not so boring and to illustrate how we can customize the reports. Of course I can’t cover all kinds of customizing but I think these customizations will be most asked for. All reports are embedded report (that means you don’t see .rdlc file at output folder). Now let’s create a console project to play around with Report Viewer. A report contains always 2 parts: data and template. So I need some data sources to feed Report Viewer. I have prepared some classes as VOs (ValueObject) containing our data and I will display values of these objects on report file. PDF and Image report use same data source (Example 1 and 3), Excel uses another ones (Example 2). These classes can be found in attachment at the end of post.

I. PDF Report
1. Right click on project and choose “Add New Item” –> Report –> Give “ReportMetaDataMember.rdlc” as new item’s name.

Add new report item

2. A new report design window will be opened. In this window, I can define how my report looks like when printing but let’s choose a data source for it first. In “Report Data” window click on New -> DataSet.

New DataSet

Enter MetaDataMember as Name, click on button new at Data source. On the new opened window, choose Object –> MetaDataDoc –> Click Finish. Go back to DataSet property choose MetaDataDoc (Members) in available datasets –> Click OK. At the end I have “Dataset Properties” as image below

Dataset Properties

3. Now I can feed my report with data. It’s the first part of what a report needs. The second part is the template. From Toolbox window, drag and drop a table on .rdlc designer then drag each property of VO to a column of table but Icon property. The icon property is an image property. However if I use Image type and I drag and drop this property whose type is Image on designer, I can’t show it on the report. The report will only show the name of property type. Therefore to show image on report, I need to convert it to byte array, and in the report template, I use Image control to parse this byte array.

public byte[] Icon 
{
	get 
	{
		Bitmap result = null;
		if (Name.StartsWith("T:"))
			result = Properties.Resources.Auto_icon;
		else if (Name.StartsWith("M:"))
			result = Properties.Resources.EVE_icon;
		else if (Name.StartsWith("F:"))
			result = Properties.Resources.M_O_icon;
		else if (Name.StartsWith("P:"))
			result = Properties.Resources.Wall_E_icon;
		else
			result = Properties.Resources.Wall_E_icon;

		MemoryStream ms = new MemoryStream();
		result.Save(ms, ImageFormat.Png);
		ms.Flush();
		return ms.ToArray();
	}
}

Image Properties

4. If I don’t use Image in data source but would like to link it from external source like file on disk. I can add a parameter to “Report Data” and pass the link of image to this parameter. In Windows “Report Data”, right click on “Parameters” folder –> Add Parameter

Report Data Add Parameter

On “Report Parameter Properties”, set name as “LogoPath” and data type as “Text”

Report Parameter Properties

Go back to design window, insert an image control and set its properties like image below

Image Properties

As you can see, the image source is set as External and its expression is linked to the parameter added before “= “file:\\\” & Parameters!LogoPath.Value“. Now I have a simple template to display my data. I can customize my report more likely
– Add Page Footer and Page number (from Built-in Fields at Report Data)

Page Footer

– Add Sorting, for example according to Name and Summary

Row Groups Details

Group Properties Sorting

– Repeat table header on new page

Advanced Mode

Repeat on new page

Play around with report designer as long as you want until the template satisfies you. After finishing with template, I need to write code to use this template for printing to pdf file.

internal class PDFReportGenerator
{
	private IEnumerable<MetaDataMember> members;

	public PDFReportGenerator(IEnumerable<MetaDataMember> members)
	{
		this.members = members;
	}

	public byte[] CreateReport()
	{
		byte[] result = null;

		using (LocalReport localReport = new LocalReport())
		{
			localReport.ReportEmbeddedResource = "RDLC_as_embedded_resource.ReportMetaDataMember.rdlc";
			localReport.DataSources.Add(new ReportDataSource("MetaDataMember", members));

			localReport.EnableExternalImages = true;
			ReportParameter logoParam = new ReportParameter("LogoPath");
			logoParam.Values.Add(Path.Combine(Application.StartupPath, "Logo.png"));
			localReport.SetParameters(new ReportParameter[] { logoParam });

			string mimeType, encoding, fileNameExtension, deviceInfo;
			string[] streams;
			Warning[] warnings;
			deviceInfo =
				"<DeviceInfo>" +
				"	<SimplePageHeaders>True</SimplePageHeaders>" +
				"</DeviceInfo>";

			result = localReport.Render(
				"PDF",
				deviceInfo,
				out mimeType,
				out encoding,
				out fileNameExtension,
				out streams,
				out warnings);

			if (warnings.Length > 0)
				foreach (Warning warning in warnings)
					Console.WriteLine(warning.Message);
		}
		return result;
	}
}

The code is pretty simple. It’s just a bridge between data and template. I just have to initialize a LocalReport, set its ReportEmbeddedResource to report template and add data to data source. The value of parameter must be added before calling printing function (I have inserted a parameter LogoPath in template before). I intend to use external image as logo therefore the EnableExternalImages must be set to true. Call the generator with data and I will have a PDF report as output

string fileName = "Read Metadata from Assembly.XML";
XDocument doc = XDocument.Load(fileName);
MetaDataDoc metadataDoc = (from d in doc.Descendants("doc")
						   select new MetaDataDoc(d)).FirstOrDefault();

IEnumerable<MetaDataMember> members = metadataDoc.Members;
PDFReportGenerator reportGenerator = new PDFReportGenerator(members);
byte[] pdf = reportGenerator.CreateReport();
File.WriteAllBytes("test.pdf", pdf);
Process.Start("test.pdf");

PDF Report Output

II. Excel report
In this second part, I will discuss about Excel report with Master/Details relationship. It’s pretty simple to create this kind of report. The simply implemented master/details need at least 2 (or more) report templates. One is for master and the other is for details. The detail template will be referenced in master template through inserting a Subreport component in master and set its properties to detail one

Subreport properties

Master report

The most important thing at master/details view is the relationship of parameters. Which property of master object will be used to categorize the children? In this example, the property “EmployeeID” of detailed part will be linked with ID of parent object

Subreport Properties Parameters

The code will be fast as same as the one for PDF report. However I must handle the Event SubreportProcessing to give the correct sub data for each parent object

internal class ExcelReportGenerator
{
	private IEnumerable<Employee> members;

	public ExcelReportGenerator(IEnumerable<Employee> members)
	{
		this.members = members;
	}

	public byte[] CreateReport()
	{
		byte[] result = null;

		using (LocalReport localReport = new LocalReport())
		{
			localReport.ReportEmbeddedResource = "RDLC_as_embedded_resource.ReportMetaDataMemberMaster.rdlc";
			localReport.DataSources.Add(new ReportDataSource("Employee", members));

			localReport.SubreportProcessing += new SubreportProcessingEventHandler(localReport_SubreportProcessing);

			string mimeType, encoding, fileNameExtension, deviceInfo;
			string[] streams;
			Warning[] warnings;
			deviceInfo =
				"<DeviceInfo>" +
				"	<SimplePageHeaders>True</SimplePageHeaders>" +
				"</DeviceInfo>";

			result = localReport.Render(
				"Excel",
				deviceInfo,
				out mimeType,
				out encoding,
				out fileNameExtension,
				out streams,
				out warnings);

			if (warnings.Length > 0)
				foreach (Warning warning in warnings)
					Console.WriteLine(warning.Message);
		}
		return result;
	}

	private void localReport_SubreportProcessing(object sender, SubreportProcessingEventArgs e)
	{
		string employeeId = e.Parameters["EmployeeID"].Values[0];
		string dataSourceName = e.DataSourceNames[0];
		IEnumerable<Phone> phones = members.Where(x => x.ID.ToString() == employeeId).Select(x => x.Phone).FirstOrDefault();
		e.DataSources.Add(new ReportDataSource(dataSourceName, phones));
	}
}

The master/details in Excel report displays the data like image below

Excel Report

III. Image report with multi-column
Now we reach the last supported type of Report Viewer. There’s nothing much to say with this kind of report. Instead of PDF exporting, I’ll export data in .tiff format. Of course I still need a template to define how the data looks like at the end. The report page of image example will be split into 2 columns. To do this, just right click out of the body template, choose “Report Properties” and Column property tells how many columns will be used in each report page. The code for image report is exactly same as in PDF report. I just replace the export type from “PDF” to “Image”.

Report Properties

Column Property

I have discussed all of 3 kinds of Report Viewer. It plays no role which kind of report, it’s just output format. What is more important is the customizing which you can only learn through more practicing and complete source code can be downloaded as “RDLC as embedded resource

Happy New Year 2012

New year is front of the door. Somewhere in the world has already started with first day in year 2012, 01-01-2012. Last year was a busy year for me and therefore I have not much time for writing blogs. However I always try to keep it update with interesting and qualified blogs as I can and I hope that these blogs can help you to solve your problem somehow. In next year maybe I will be more busier. Time for family, time for work, time for something new,… I can’t promise for writing many blogs but I’ll do my best to write more practical and helpful blogs. Wishing you health and happiness in the year to come and below are the video which I took from my appartment in Obersendling, Munich. There is no big fireworks show in Munich, the people buy the fireworks themselves and celebrate exactly at 0:00 on 01.01.2012 with their own show.

Best new year wishes

1. May each moment of this year be special, filling your heart with immense pleasure and may each day turn out just the way you want it to be. Have a splended new year.

2. Today 3 people ask me about you. I gave them your details and contact. They’ll be finding you soon. Their names are Happiness, Wealth and Love. Cheers – Happy New Year!

3. You know God arrange for you..
12 Months of Love,
52 Weeks non stop Fun,
365 days of Happiness.
So when you mixed them all..
You will found a very happy year! & I think it’s 2012. My Dear.


4. When you’re lonely, I wish you Love! When you’re down, I wish you Joy! When you’re troubled, I wish you Peace! When things seem empty, I wish you Hope! Have a Happy New Year!


Morning brings Hope, Afternoon brings Faith,Evening brings Love,Night brings Rest,Hope you will have all of them everyday.Happy New Year!

5. A life of Joy, a joyful Spirit, a spiritual Body, a body full of Health, a healthy Heart, a heart full of Love, a love with Soul, a soulful Happiness & a Happy New Year! All these are my prayers for you!

6. New Year begins, let us pray, that it will be a year with new Peace, new Happiness, and Abundance of new friends. God bless you through out the new year.

7. New Year is the time to unfold new horizons and realize new dreams, to rediscover the strength and faith within you, to rejoice in simple pleasures and gear up for a new challenges. Wishing you a truly fulfilling 2012

8. Ring out the old, ring in the new,
Ring happy bells, across the snow,
The year is going, let him go;
Ring out the false, ring in the true.
Happy New Year…

9. On the onset of New Year
Sending you the warmest of wishes
Have a promising and fulfilling New Year
With lots of joy and happiness


10. Keep the smile,
Leave the tear,
Think of joy,
Forget the fear,
Hold the laugh,
Leave the pain,
Be joyous,
Coz it’s new year!
Happy New Year!