Skip to main content Skip to footer

Printing with PdfViewer for WinRT

After loading a PDF with the C1PdfViewer control, you can obtain a list of its pages as FrameworkElements to customize how the user views each page. Just call the GetPages method. This enables a lot more flexibility in working with existing PDF documents. One example is you can send the page images to a printing-enabled device on Windows 8. Printing C1PdfViewer is a built-in feature in the Silverlight and WPF versions, but for WinRT XAML it’s a bit different. WinRT XAML apps require that you register your app with the Devices charm to integrate with the Windows 8 printing experience. Or at least that’s the preferred way to enable printing. This blog post describes how you can enable printing with the C1PdfViewer control for WinRT XAML. You can download the complete sample below or continue on to learn how it all goes together. Download PdfViewerPrint Sample

Invoke the Print

First, let’s kick off the printing with a PRINT button in our application. Add the following code to the click event of any button.


private async void btnPrint\_Click\_1(object sender, RoutedEventArgs e)  
{  
    // Don't act when in snapped mode  
    if (ApplicationView.Value != ApplicationViewState.Snapped)  
    {  
        await Windows.Graphics.Printing.PrintManager.ShowPrintUIAsync();  

    }  
}  

All this does is show the light dismiss pop-out of the available Print devices. This is the same as the user hitting the Devices charm, except it shows just printers only. After we’re done, we won’t actually need this button to invoke printing. Users will be able to swipe the Devices charm to print as well. But having a button can be good as it teaches users that they can print from your app. Printing is probably not as intuitive on Windows 8 as, say, Search or Share, so many users may not even know printing is possible unless you display the option in your UI somewhere.

Register the Print Task

Next we need to create a PrintManager for the current view and handle its PrintTaskRequested event in order to capture the user’s request. In the RegisterForPrinting method below we create the PrintManager, as well as instantiate a PrintDocument object that will be used to prepare pages for printing. We will do the actual preparing in the Paginate, GetPreviewPages and AddPages events later.


// PrintDocument is used to prepare the pages for printing.  
protected PrintDocument printDocument = null;  

// Marker interface for document source  
protected IPrintDocumentSource printDocumentSource = null;  
// This method registers the app for printing with Windows and sets up the necessary event handlers for the print process.  
protected void RegisterForPrinting()  
{  
    // Create the PrintDocument.  
    printDocument = new PrintDocument();  

    // Save the DocumentSource.  
    printDocumentSource = printDocument.DocumentSource;  

    // Add an event handler which creates preview pages.  
    printDocument.Paginate += Paginate;  

    // Add an event handler which provides a specified preview page.  
    printDocument.GetPreviewPage += GetPrintPreviewPage;  

    // Add an event handler which provides all final print pages.  
    printDocument.AddPages += AddPrintPages;  

    // Create a PrintManager and add a handler for printing initialization.  
    PrintManager printMan = PrintManager.GetForCurrentView();  
    printMan.PrintTaskRequested += PrintTaskRequested;  
}  

You can call the RegisterForPrinting method within the page’s OnNavigatedTo event.


protected override void OnNavigatedTo(NavigationEventArgs e)  
{  
    // init printing  
    RegisterForPrinting();  
}  

Now is when the magic begins to happen with C1PdfViewer. At this point you’d normally have to write your own logic to transform your content into print documents. That can be a lot of work, but with the C1PdfViewer control all of that work is done already. The control’s GetPages method returns a collection of pages as FrameworkElements – ready to print. And we can also quickly get the PageCount. The Paginate event occurs when the PrintManager requests a print preview. In here you can set the total page count.


// This is the event handler for PrintDocument.Paginate.  
// It fires when the PrintManager requests print preview  
protected void Paginate(object sender, PaginateEventArgs e)  
{  
    PrintDocument printDoc = (PrintDocument)sender;  

    // Report the number of preview pages  
    printDoc.SetPreviewPageCount(c1PdfViewer1.PageCount, PreviewPageCountType.Intermediate);  
}  

The GetPrintPreviewPage event provides a specific print preview page to a PrintDocument that the Windows print system can deal with. This is fired each time the user attempts to preview a specific page in the print preview pop-out.


// This is the event provides a specific print preview page  
protected void GetPrintPreviewPage(object sender, GetPreviewPageEventArgs e)  
{  
    PrintDocument printDoc = (PrintDocument)sender;  

    printDoc.SetPreviewPage(e.PageNumber, pages[e.PageNumber - 1]);  
}  

You will notice there is a pages collection. In my sample I populated a separate collection of the pages from my PDF. This helps reduce the number of times we call the C1PdfViewer.GetPages method, because otherwise we end up calling it at least three times. Somewhere in your page load or constructor, instantiate and populate the pages collection.


// A list of UIElements used to store the pdf pages.  This gives easy access  
// to any desired page without having to call c1PdfViewer.GetPages multiple times  
internal List<FrameworkElement> pages = null;  
// Store pages from PdfViewer  
pages = new List<FrameworkElement>();  
foreach (FrameworkElement page in c1PdfViewer1.GetPages())  
{  
    pages.Add(page);  
}  

Complete Printing

When the user requests a print task we have to handle the PrintManager.PrintTaskRequested event. This event is responsible for creating the print task. It’s in this event that you can specify the title of the printed document, catch any errors, as well as set print options like page orientation and paper size. In our code below, we check whether the PDF is Landscape and try to set the orientation for the user.


// This is the event handler for PrintManager.PrintTaskRequested.  
protected void PrintTaskRequested(PrintManager sender, PrintTaskRequestedEventArgs e)  
{  
    PrintTask printTask = null;  
    printTask = e.Request.CreatePrintTask("SamplePDF", sourceRequested =>  
    {  
        // Print Task event handler is invoked when the print job is completed.  
        printTask.Completed += async (s, args) =>  
        {  
            // Notify the user when the print operation fails.  
            if (args.Completion == PrintTaskCompletion.Failed)  
            {  
                await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>  
                {  
                    MessageDialog dialog = new MessageDialog("Failed to print.");  
                    dialog.ShowAsync();  
                });  
            }  
        };  

        // set print options like paper size and orientation  
        Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>  
        {  
            if (pages[0].ActualWidth > pages[0].ActualHeight)  
            {  
                printTask.Options.Orientation = PrintOrientation.Landscape;  
            }  
        });  

        sourceRequested.SetSource(printDocumentSource);  
    });  

}  

The second-to-last step to complete the printing is to handle the PrintDocument.AddPages event. It provides all pages to be printed in the form of FrameworkElements (or UIElements) to an instance of PrintDocument. PrintDocument subsequently converts the elements into printable pages. This event is fired when the user hits the Print button from within the Device Printer pop-out.


// This is the event provides all pages to be printed, in the form of  
// UIElements, to an instance of PrintDocument.  
protected void AddPrintPages(object sender, AddPagesEventArgs e)  
{  
    // Loop over all of the pages and add each one to be printed  
    foreach (FrameworkElement page in pages)  
    {  
        printDocument.AddPage(page);  
    }  

    PrintDocument printDoc = (PrintDocument)sender;  

    // Indicate that all of the print pages have been provided  
    printDoc.AddPagesComplete();  
}  

Finally, we should unregister printing capabilities from this page of our application (so users can only print from the page containing PdfViewer).


protected override void OnNavigatedFrom(NavigationEventArgs e)  
{  
    UnregisterForPrinting();  
}  
// This method unregisters the app for printing with Windows.  
protected void UnregisterForPrinting()  
{  
    if (printDocument == null)  
        return;  

    printDocument.Paginate -= Paginate;  
    printDocument.GetPreviewPage -= GetPrintPreviewPage;  
    printDocument.AddPages -= AddPrintPages;  

    // Remove the handler for printing initialization.  
    PrintManager printMan = PrintManager.GetForCurrentView();  
    printMan.PrintTaskRequested -= PrintTaskRequested;  

}  

That completes this printing tutorial. You can download the complete sample below. Download PdfViewerPrint Sample

ComponentOne Product Manager Greg Lutz

Greg Lutz

comments powered by Disqus