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.
ReportDocument reportDocument = new ReportDocument();
Next, we need to supply a template for our report.
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:
<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 x:Key="headerFooterRowStyle"
TargetType="{x:Type TableRowGroup}">
<Setter Property="FontWeight" Value="DemiBold"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="Background" Value="LightGray"/>
</Style>
<Style x:Key="dataRowStyle" TargetType="{x:Type TableRowGroup}">
<Setter Property="FontSize" Value="12"/>
</Style>
<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…
ReportData data = new ReportData();
First add some “metadata”:
data.ReportDocumentValues.Add("PrintDate", DateTime.Now);
And then the DataTables
:
data.DataTables.Add(table);
Here, table
is of type DataTable
.
And that is it!
Finally export it to Xps
and show:
XpsDocument xps = reportDocument.CreateXpsDocument(data);
You can use the standard DocumentViewer
to display the report.
Read More
CodeProject