C# WPF Print page number on every page of a flow document

399 Views Asked by At

I am trying to print a flowdocument with the number of the corresponding page on each page.

What is the best way to do this? Directly on the flowdocument or on the PrintDialog?

I've been searching for this but without success.

Thanks in advance.

private void Btn_print_Click(object sender, RoutedEventArgs e)
        {
           

            PrintDialog pd = new PrintDialog();
            if (pd.ShowDialog() == true)
            {
                IDocumentPaginatorSource idp = FlowDoc;
                pd.PrintDocument(idp.DocumentPaginator, "Flow Document");
            }
            

        }
2

There are 2 best solutions below

2
Gehan Fernando On

The code includes comments to explain each step of the process

using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Print_Click(object sender, RoutedEventArgs e)
    {
        PrintDialog pd = new PrintDialog();
        if (pd.ShowDialog() == true)
        {
            // Create a new FlowDocument
            FlowDocument flowDoc = new FlowDocument();
            flowDoc.PagePadding = new Thickness(50);
            flowDoc.PageHeight = pd.PrintableAreaHeight;
            flowDoc.PageWidth = pd.PrintableAreaWidth;

            // Add content to the FlowDocument
            Paragraph para1 = new Paragraph(new Run("This is paragraph 1."));
            Paragraph para2 = new Paragraph(new Run("This is paragraph 2."));
            flowDoc.Blocks.Add(para1);
            flowDoc.Blocks.Add(para2);

            // Add a header to the FlowDocument that displays the current page number
            AddHeader(flowDoc);

            // Set the PageRangeSelection and UserPageRangeEnabled properties to allow the user to choose which pages to print
            pd.PageRangeSelection = PageRangeSelection.UserPages;
            pd.UserPageRangeEnabled = true;

            // Print the FlowDocument
            pd.PrintDocument(flowDoc.DocumentPaginator, "Flow Document");
        }
    }

    private void AddHeader(FlowDocument flowDoc)
    {
        // Create a Paragraph to hold the page number information
        Paragraph paragraph = new Paragraph();
        paragraph.TextAlignment = TextAlignment.Center;
        paragraph.FontSize = 12;
        paragraph.Inlines.Add(new Run("Page "));
        paragraph.Inlines.Add(new Run(new Bold(new Run("{0}"))));
        paragraph.Inlines.Add(new Run(" of "));
        paragraph.Inlines.Add(new Run(new Bold(new Run("{1}"))));

        // Format the string using the current page number and the total page count
        string headerText = string.Format("Page {0} of {1}", "{PageNumber}", "{PageCount}");

        // Substitute the header text into the Runs that represent the page number and page count
        ((Bold)paragraph.Inlines.ElementAt(1)).Inlines.Add(new Run(headerText));
        ((Bold)paragraph.Inlines.ElementAt(3)).Inlines.Add(new Run(headerText));

        // Create a FixedPage to hold the Paragraph
        FixedPage fixedPage = new FixedPage()
        {
            Width = flowDoc.PageWidth,
            Height = flowDoc.PageHeight,
        };
        BlockUIContainer container = new BlockUIContainer();
        container.Child = paragraph;
        fixedPage.Children.Add(container);

        // Add the FixedPage to the PageHeader property of the FlowDocument
        flowDoc.PageHeader = fixedPage;
    }
}
0
Costa On

Well I manage to do this by cloning the flowdocument :

 private void PrintButton_Click(object sender, RoutedEventArgs e)
    {
        // Load the existing FlowDocument from XAML or any other source
        FlowDocument flowDocument = FlowDoc;

        // Clone the FlowDocument to keep the original intact
        FlowDocument clonedFlowDocument = CloneFlowDocument(flowDocument);

        // Set the PageWidth and PageHeight of the cloned FlowDocument
        SetPageDimensions(clonedFlowDocument, 1100, 1500);

        // Print the cloned FlowDocument with the PrintDialog
        PrintDialog printDialog = new PrintDialog();

        if (printDialog.ShowDialog() == true)
        {
            // Create a CustomPaginator using the cloned FlowDocument
            CustomPaginator paginator = new CustomPaginator(((IDocumentPaginatorSource)clonedFlowDocument).DocumentPaginator, new Typeface("Arial"), 12, Brushes.Black, 96);

            // Set the PageSize of the CustomPaginator to match the print dialog settings
            paginator.PageSize = new Size(printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight);

            // Print the CustomPaginator with the PrintDialog
            printDialog.PrintDocument(paginator, "Print Job");
        }
    }


    private FlowDocument CloneFlowDocument(FlowDocument flowDocument)
    {
        // Serialize the FlowDocument to XAML and then load it back to create a clone
        string xaml = XamlWriter.Save(flowDocument);
        return (FlowDocument)XamlReader.Parse(xaml);
    }

    private void SetPageDimensions(FlowDocument flowDocument, double pageWidth, double pageHeight)
    {
        // Set the PageWidth and PageHeight of the FlowDocument
        flowDocument.PageWidth = pageWidth;
        flowDocument.PageHeight = 1550;
        flowDocument.PagePadding = new Thickness(20);
    }

an then making a custom paginator class like this:

 using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Shapes;

public class CustomPaginator : DocumentPaginator
{
    private readonly DocumentPaginator _paginator;
    private readonly Typeface _typeface;
    private readonly double _fontSize;
    private readonly Brush _brush;
    private readonly double _pixelsPerDip;

    public CustomPaginator(DocumentPaginator paginator, Typeface typeface, double fontSize, Brush brush, double pixelsPerDip)
    {
        _paginator = paginator;
        _typeface = typeface;
        _fontSize = fontSize;
        _brush = brush;
        _pixelsPerDip = pixelsPerDip;
    }

    public override DocumentPage GetPage(int pageNumber)
    {
        DocumentPage page = _paginator.GetPage(pageNumber);

        // Create a container to hold the original page content
        ContainerVisual container = new ContainerVisual();
        container.Children.Add(page.Visual);

        // Add page number to the container
        DrawingVisual pageNumberVisual = new DrawingVisual();
        using (DrawingContext dc = pageNumberVisual.RenderOpen())
        {
            double pixelsPerDip = VisualTreeHelper.GetDpi(page.Visual).PixelsPerDip;
            FormattedText formattedText = new FormattedText(
                $"Page {pageNumber + 1}",
                CultureInfo.CurrentCulture,
                FlowDirection.LeftToRight,
                _typeface,
                _fontSize,
                _brush,
                pixelsPerDip);

            double x = page.ContentBox.Left + (page.ContentBox.Width - formattedText.Width) / 2;
            double y = page.ContentBox.Bottom - formattedText.Height - 10; // Adjust the position as needed

            dc.DrawText(formattedText, new Point(x, y));
        }

        container.Children.Add(pageNumberVisual);

        // Return a new DocumentPage with the modified container
        return new DocumentPage(container, page.Size, page.BleedBox, page.ContentBox);
    }



    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;
}

Hope this helps someone.