I've an ICommand
, PrintReport. Its execute function does this:
void printReport(object o)
{
var dialog = new PrintDialog()
{
CurrentPageEnabled = true,
UserPageRangeEnabled = true
};
if (dialog.ShowDialog() == true)
{
var size = new Size(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight);
FlowPaginator.PageWidth = size.Width;
FlowPaginator.PageHeight = size.Height;
CreateReport(size);
dialog.PrintDocument(new FlowPaginator(document) { PageSize = size }, string.Empty);
}
}
FlowPaginator
is a subclass of DocumentPaginator
and I couldn't find any way of adding Header and Footer in my FlowDocument
directly when I create that so I add those in this class,. First, I create the FlowDocument
, document, and then pass that in the new FlowPaginator
in PrintDocument
method.
void CreateReport(Size pageSize)
{
document = new FlowDocument()
{
PageWidth = pageSize.Width,
PageHeight = pageSize.Height,
PagePadding = new Thickness(FlowPaginator.Margin,
Header(pageSize).DesiredSize.Height,
FlowPaginator.Margin,
FlowPaginator.Margin)
};
var table = new Table()
{
FontFamily = SystemFonts.MessageFontFamily,
FontStyle = SystemFonts.MessageFontStyle,
FontSize = 11.0,
CellSpacing = 0,
Columns =
{
new TableColumn(){ Width = new GridLength(ColumnWidth) },
new TableColumn(){ Width = new GridLength(pageSize.Width - (2.0 * FlowPaginator.Margin) - (4 * ColumnWidth)) },
new TableColumn(){ Width = new GridLength(ColumnWidth) },
new TableColumn(){ Width = new GridLength(ColumnWidth) },
new TableColumn(){ Width = new GridLength(ColumnWidth) },
}
};
var rowNum = 1;
foreach (var item in Reportables)
{
var rowGroup = new TableRowGroup();
var row = new TableRow();
row.Cells.Add(new TableCell(new Paragraph(new Run(item.Date.ToString("dd/MM/yyyy")))));
row.Cells.Add(new TableCell(new Paragraph(new Run(item.Particulars))));
row.Cells.Add(new TableCell(new Paragraph(new Run(item.Receivable.ToString("#,##0;(#,##0);- ")))) { TextAlignment = TextAlignment.Right });
row.Cells.Add(new TableCell(new Paragraph(new Run(item.Receipt.ToString("#,##0;(#,##0);- ")))) { TextAlignment = TextAlignment.Right });
row.Cells.Add(new TableCell(new Paragraph(new Run(item.Balance.ToString("#,##0;(#,##0);- ")))) { TextAlignment = TextAlignment.Right });
if (rowNum % 2 == 0) row.Background = Brushes.LightBlue;
rowGroup.Rows.Add(row);
table.RowGroups.Add(rowGroup);
rowNum++;
}
document.Blocks.Add(table);
}
To have room for the Header on every page of the Flowdocument
I call a function, Header(pageSize).DesiredSize.Height
which returns an UIElement
, in PagePadding
. and for each column of my tabular report, I specify the TableColumn
Width. The FlowPaginator
class have these in it:
public class FlowPaginator : DocumentPaginator
{
public static double PageWidth, PageHeight;
public const double Margin = 96.0;
DocumentPaginator paginator;
public FlowPaginator(FlowDocument document)
{
paginator = ((IDocumentPaginatorSource)document).DocumentPaginator;
}
public override bool IsPageCountValid => paginator.IsPageCountValid;
public override int PageCount => paginator.PageCount;
public override Size PageSize { get => paginator.PageSize; set => paginator.PageSize = value; }
public override IDocumentPaginatorSource Source => paginator.Source;
public override DocumentPage GetPage(int pageNumber)
{
return new DocumentPage(new ContainerVisual()
{
Children =
{
LedgerVM.Header(PageSize),
paginator.GetPage(pageNumber).Visual,
Footer(++pageNumber)
}
});
}
UIElement Footer(int pageNo){ ... }
}
Here in the GetPage
, I've to call the same static Header
function, used in the CreateReport
method, to add the header, then the padded content and finally have to call another function of the same class, Footer
, to get footer on every page.
I wanted to use GridUnitType.Star
for the second column of the FlowDocument
and GridLength.Auto
for the rest of the 4 columns BUT I haven't found any way of doing that so far and also wanted to add Header/Footer directly in the FlowDocument
when I Create it, is there any way to do these or can this process be simplified further?