Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

Open-Source WPF Reporting Engine

4.00/5 (4 votes)
1 Apr 2010CPOL1 min read 1  
I have seen so many people use FlowDocuments to create reports! This is really cool but what if you need a more complex reporting engine! Can it handle it? Can it be abstracted and reused! Do you have to start from scratch each time?

Reporting is one of those things that we hate but can't live without!

WPF is a awesome platform with so many powerful controls available! I have seen so many people use FlowDocuments to create reports! This is really cool but what if you need a more complex reporting engine! Can it handle it? Can it be abstracted and reused! Do you have to start from scratch each time?

Introducing Open-Source .NET WPF Reporting Engine

“This project allows you to create reports using WPF (Windows Presentation Foundation). Its supports headers and footers, DataTable binding, barcode generation, XPS creation and more.”

First things, first… Create a ReportDocument. This is the “container" for our report.

C#
ReportDocument reportDocument = new ReportDocument();

Next, we need to supply a template for our report. 

C#
StreamReader reader = new StreamReader
  (new FileStream(@"Templates\SimpleReport.xaml", FileMode.Open, FileAccess.Read)); 
reportDocument.XamlData = reader.ReadToEnd(); 
reportDocument.XamlImagePath = Path.Combine(Environment.CurrentDirectory, @"Templates\"); 
reader.Close();

Here is how our template looks:

XML
<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:xrd="clr-namespace:CodeReason.Reports.Document;
		assembly=CodeReason.Reports" 
              PageHeight="29.7cm" PageWidth="21cm" ColumnWidth="21cm">
    <xrd:ReportProperties>
        <xrd:ReportProperties.ReportName>SimpleReport</xrd:ReportProperties.ReportName>
        <xrd:ReportProperties.ReportTitle>Simple Report
        </xrd:ReportProperties.ReportTitle>
    </xrd:ReportProperties>
    <Section Padding="80,10,40,10" FontSize="12">
        <Paragraph FontSize="24" FontWeight="Bold">
            <xrd:InlineContextValue PropertyName="ReportTitle" />
        </Paragraph>
        <Paragraph>This is a simple report example that contains a table.
            The table is filled using a DataTable object.</Paragraph>
        <xrd:SectionDataGroup DataGroupName="ItemList">
            <Paragraph FontSize="20" FontWeight="Bold">Item List</Paragraph>
            <Table CellSpacing="0" BorderBrush="Black" BorderThickness="0.02cm">
                <Table.Resources>
                    <!-- Style for header/footer rows. -->
                    <Style x:Key="headerFooterRowStyle" 
			TargetType="{x:Type TableRowGroup}">
                        <Setter Property="FontWeight" Value="DemiBold"/>
                        <Setter Property="FontSize" Value="16"/>
                        <Setter Property="Background" Value="LightGray"/>
                    </Style>

                    <!-- Style for data rows. -->
                    <Style x:Key="dataRowStyle" TargetType="{x:Type TableRowGroup}">
                        <Setter Property="FontSize" Value="12"/>
                    </Style>

                    <!-- Style for data cells. -->
                    <Style TargetType="{x:Type TableCell}">
                        <Setter Property="Padding" Value="0.1cm"/>
                        <Setter Property="BorderBrush" Value="Black"/>
                        <Setter Property="BorderThickness" Value="0.01cm"/>
                    </Style>
                </Table.Resources>

                <Table.Columns>
                    <TableColumn Width="0.5*" />
                    <TableColumn Width="2*" />
                    <TableColumn Width="*" />
                    <TableColumn Width="0.5*" />
                </Table.Columns>
                <TableRowGroup Style='{StaticResource headerFooterRowStyle}'>
                    <TableRow>
                        <TableCell>
                            <Paragraph TextAlignment='Center'>
                                <Bold>Pos.</Bold>
                            </Paragraph>
                        </TableCell>
                        <TableCell>
                            <Paragraph TextAlignment='Center'>
                                <Bold>Item Name</Bold>
                            </Paragraph>
                        </TableCell>
                        <TableCell>
                            <Paragraph TextAlignment='Center'>
                                <Bold>EAN</Bold>
                            </Paragraph>
                        </TableCell>
                        <TableCell>
                            <Paragraph TextAlignment='Center'>
                                <Bold>Count</Bold>
                            </Paragraph>
                        </TableCell>
                    </TableRow>
                </TableRowGroup>
                <TableRowGroup Style='{StaticResource dataRowStyle}'>
                    <xrd:TableRowForDataTable TableName='Ean'>
                        <TableCell>
                            <Paragraph>
                                <xrd:InlineTableCellValue PropertyName='Position' />
                            </Paragraph>
                        </TableCell>
                        <TableCell>
                            <Paragraph>
                                <xrd:InlineTableCellValue PropertyName='Item' />
                            </Paragraph>
                        </TableCell>
                        <TableCell>
                            <Paragraph>
                                <xrd:InlineTableCellValue PropertyName='EAN'/>
                            </Paragraph>
                        </TableCell>
                        <TableCell>
                            <Paragraph TextAlignment='Center'>
                                <xrd:InlineTableCellValue PropertyName='Count' 
				AggregateGroup='ItemCount'/>
                            </Paragraph>
                        </TableCell>
                    </xrd:TableRowForDataTable>
                </TableRowGroup>
            </Table>
            <Paragraph>
                There are
                <xrd:InlineAggregateValue AggregateGroup='ItemCount' 
		AggregateValueType='Count' EmptyValue='no' FontWeight='Bold' /> 
		item positions with a total of
                <xrd:InlineAggregateValue AggregateGroup='ItemCount' 
		AggregateValueType='Sum' EmptyValue='0' FontWeight='Bold' /> 
		items listed.
            </Paragraph>
        </xrd:SectionDataGroup>
    </Section>
</FlowDocument>

I will go into more detail on how to customize this template in future posts. Now the data…

C#
ReportData data = new ReportData();

First add some “metadata”:

C#
data.ReportDocumentValues.Add("PrintDate", DateTime.Now);

And then the DataTables:

C#
data.DataTables.Add(table);

Here, table is of type DataTable.

And that is it!

Finally export it to Xps and show:

C#
XpsDocument xps = reportDocument.CreateXpsDocument(data);

You can use the standard DocumentViewer to display the report.

Read More

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)