Windows 8 Print Contract – Create Your Own Print Document Source

November 3, 2012

3 comments

Windows 8 Print Contract – Create Your Own Print Document Source

Windows 8 Print Contract – Create Your Own Print Document SourceWindows 8 includes the ability to print content from a running Windows Store app. You use the print contract to enable that ability and the Devices Charm to use it. In this post you will learn how to register for print contract and you will create your own print document source.

The Windows 8 Print Contract

When you want to enable printing in your Windows Store app, you will first need to register  all the views that can be printed to the print contract. To do that, you will need to use the PrintManager object and create a PrintTask. The PrintManager is part of the Windows.Graphics.Printing namespace. You can get the print manager for a current view by using the PrintManager’s getForCurrentView function. the following line of code will get the print manager for the current view:

var printManager = Windows.Graphics.Printing.PrintManager.getForCurrentView();

After you have the PrintManager instance, you need to add an event listener to the printtaskrequested event. The printtaskrequested event is the main event that will be fired when printing is requested by the app. Here is how to register to the printtaskrequested event:

printManager.addEventListener("printtaskrequested", onPrintTaskRequested, false);

When the event is fired, the event listener (in the previous code onPrintTaskRequested) will receive a Windows.Graphics.Printing.PrintTaskRequest parameter that can be used to create the PrintTask. You use the PrintTaskRequest’s request property and the request property’s createPrintTask function to do that. The createPrintTask function receives a task name and an event listener to configure the print task. Here is a snippet for onPrintTaskRequested function:

function onPrintTaskRequested(printEvent) {
    var printTask = printEvent.request.createPrintTask("Print Example", function (args) {
        ...
    });
}

If you want to do something when printing finishes, you can register to the PrintTask’s complete event. The following code example shows how to register to the complete event:

function onPrintTaskRequested(printEvent) {
        var printTask = printEvent.request.createPrintTask("Print Example", function (args) {
            ...
          
            // Register a  handler for print task completion event
            printTask.addEventListener("completed", onPrintTaskCompleted, false);
        });
    }

In the complete event handler, you receive a Windows.Graphics.Printing.PrintTaskCompleted parameter which has a completion property. The completion property can have values to indicate the state of the completion. The Windows.Graphics.Printing.PrintTaskCompletion object includes all these state such as failed and submitted. Here is a simple event listener to the complete event:

function onPrintTaskCompleted(printTaskCompletionEvent) {
    if (printTaskCompletionEvent.completion === Windows.Graphics.Printing.PrintTaskCompletion.failed) {
        // do something when the print task failed
    }
}

All the printing set up should be done in the ready function of the view.

Printing Content

In the previous section, you saw how to register for the print contract. But how can you instruct the runtime which content to print? In the event handler of printtaskrequested you set the print source.

The easiest way to set a print source is to use the current view document object and to print all the view content. The following example shows the simplest way to implement the onPrintTaskRequested function:

function onPrintTaskRequested(printEvent) {
    var printTask = printEvent.request.createPrintTask("Print Example", function (args) {
        args.setSource(MSApp.getHtmlPrintDocumentSource(document));
 
        // Register the handler for print task completion event
        printTask.oncompleted = onPrintTaskCompleted;
    });
}

As you can see, the PrintTask args property has a setSource function that is used to set the printing source. The setSource function receives a print document source which should be created using the MSApp.getHtmlPrintDocumentSource function. The getHtmlPrintDocumentSource receives the document object to print and in the example it is using the view document object.

Print Your Own Document Source

But what if you want to create your own print view? You just use the document.createDocumentFragment as a document container and create your own view inside of it. The following example shows how to create your own document container:

function onPrintTaskRequested(printEvent) {
    var printTask = printEvent.request.createPrintTask("Print Example", function (args) {            
        printCurrentPage(args);
 
        // Register the handler for print task completion event
        printTask.oncompleted = onPrintTaskCompleted;
    });
}
 
function printCurrentPage(args) {
    var docHtml = document.createDocumentFragment();       
    docHtml.appendChild(createDocumentContent());
    args.setSource(MSApp.getHtmlPrintDocumentSource(docHtml));
}
 
function createDocumentContent() {
        var container = document.createElement("div");
        
        container.appendChild(WinJS.Utilities.query(".item-title")[0]);
        container.appendChild(WinJS.Utilities.query(".item-content")[0]);
 
        return container;
    }

In the example, you can see that the created document fragment is used as the source for the MSApp.getHtmlPrintDocumentSource function. The createDocumentContent function creates the relevant content that you want to print and not all the view document.

Enabling Printing Configurations

You can help the user to customize the printing experience by exposing options to choose the print orientation, number of copies and more. You can do that by using the PrintTask options property. The PrintTask options property has a displayedOptions property that is used to configure all the displayed options for printing. You first need to clear the displayed options and then append all the options that you want to show the user. The entire print options are available in the Windows.Graphics.Printing.StandardPrintTaskOptions object. Here is an example of configuring printing options:

function onPrintTaskRequested(printEvent) {
    var printTask = printEvent.request.createPrintTask("Print Example", function (args) {            
        printCurrentPage(args);
 
        printTask.options.displayedOptions.clear();
        printTask.options.displayedOptions.append(Windows.Graphics.Printing.StandardPrintTaskOptions.copies);
        printTask.options.displayedOptions.append(Windows.Graphics.Printing.StandardPrintTaskOptions.orientation);
        printTask.options.displayedOptions.append(Windows.Graphics.Printing.StandardPrintTaskOptions.colorMode);
 
        // Register the handler for print task completion event
        printTask.oncompleted = onPrintTaskCompleted;
    });
}

In the example, you can see that the user will be able to set the number of copies, set the printing orientation and set the printing color mode. You can take a look at all the printing options in this link.

Showing The Print UI

Printing is done by opening the Devices Charm. If you want to show the print charm as a reaction to an event like the click event, you can use the Windows.Graphics.Printing.PrintManager.showPrintUIAsync function. The following code will show the print UI:

Windows.Graphics.Printing.PrintManager.showPrintUIAsync();

A Full Example

To show all the printing concepts that were written in this post, I’ve created a code sample based on the Grid project template. Here is the full Print namespace which exists in the print.js file:

(function () {
    "use strict";
 
    /// <summary>
    /// Register for Print contract to enable printing. The user has to manually invoke
    /// the print charm after this function is executed.   
    /// </summary>
    function registerForPrintContract() {
        var printManager = Windows.Graphics.Printing.PrintManager.getForCurrentView();
        printManager.addEventListener("printtaskrequested", onPrintTaskRequested, false);        
    }
 
    /// <summary>
    /// Print event handler for printing via the PrintManager API. The user has to manually invoke
    /// the print charm after this function is executed.
    /// </summary>
    /// <param name="printEvent" type="Windows.Graphics.Printing.PrintTaskRequest">
    /// The event containing the print task request object.
    /// </param>
    function onPrintTaskRequested(printEvent) {
        var printTask = printEvent.request.createPrintTask("Print Example", function (args) {            
            printCurrentPage(args);
 
            printTask.options.displayedOptions.clear();
            printTask.options.displayedOptions.append(Windows.Graphics.Printing.StandardPrintTaskOptions.copies);
            printTask.options.displayedOptions.append(Windows.Graphics.Printing.StandardPrintTaskOptions.orientation);
            printTask.options.displayedOptions.append(Windows.Graphics.Printing.StandardPrintTaskOptions.colorMode);
 
            // Register the handler for print task completion event
            printTask.oncompleted = onPrintTaskCompleted;
        });
    }
 
    function printCurrentPage(args) {
        var docHtml = document.createDocumentFragment();       
        docHtml.appendChild(createDocumentContent());
        args.setSource(MSApp.getHtmlPrintDocumentSource(docHtml));
    }
    
    /// <summary>
    /// Create the elements are going to be the document content
    /// </summary>
    function createDocumentContent() {
        var container = document.createElement("div");
        
        container.appendChild(WinJS.Utilities.query(".item-title")[0]);
        container.appendChild(WinJS.Utilities.query(".item-content")[0]);
 
        return container;
    }
 
    /// <summary>
    /// Print Task event handler is invoked when the print job is completed.
    /// </summary>
    /// <param name="printTaskCompletionEvent" type="Windows.Graphics.Printing.PrintTaskCompleted">
    /// The event containing the print task completion object.
    /// </param>
    function onPrintTaskCompleted(printTaskCompletionEvent) {
        // Notify the user about the failure
        if (printTaskCompletionEvent.completion === Windows.Graphics.Printing.PrintTaskCompletion.failed) {
            WinJS.log && WinJS.log("Failed to print.", "sample", "error");
        }
    }
 
    /// <summary>
    /// Unregister for Print contract. Removes the printing option from the print charm after this function is executed.   
    /// </summary>
    function unregisterForPrintContract() {
        var printManager = Windows.Graphics.Printing.PrintManager.getForCurrentView();
        printManager.onprinttaskrequested = null;
    }
 
    /// <summary>
    /// Shows the print UI.   
    /// </summary>
    function showPrintUI() {        
        Windows.Graphics.Printing.PrintManager.showPrintUIAsync();
    }
 
    WinJS.Namespace.define("Print", {
        registerForPrint: registerForPrintContract,
        unregisterForPrint: unregisterForPrintContract,
        showPrintUI: showPrintUI        
    });
})();

In the default.html file, I’ve created an appbar with a print command:

<div id="appbar" data-win-control="WinJS.UI.AppBar">
   <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'print', label:'Print', icon:'&#x4DC0;',section:'global',tooltip:'Print'}"></button>
/div> 

In the itemDetail.js file, I’ve added to the ready function the event registration for the appbar print command which will show the print Charm:

(function () {
    "use strict";
 
    WinJS.UI.Pages.define("/pages/itemDetail/itemDetail.html", {
        // This function is called whenever a user navigates to this page. It
        // populates the page elements with the app's data.
        ready: function (element, options) {
            var item = options && options.item ? Data.resolveItemReference(options.item) : Data.items.getAt(0);
            element.querySelector(".titlearea .pagetitle").textContent = item.group.title;
            element.querySelector("article .item-title").textContent = item.title;
            element.querySelector("article .item-subtitle").textContent = item.subtitle;
            element.querySelector("article .item-image").src = item.backgroundImage;
            element.querySelector("article .item-image").alt = item.subtitle;
            element.querySelector("article .item-content").innerHTML = item.content;
            element.querySelector(".content").focus();
 
            var appbar = document.getElementById("appbar").winControl;
            appbar.showOnlyCommands(["print"]);
 
            document.getElementById('print').addEventListener('click', print, false);
            Print.registerForPrint();
        },
        unload: function () {
            document.getElementById('print').removeEventListener('click', print);
            Print.unregisterForPrint();            
        }
    });
 
    function print() {
        Print.showPrintUI();
    }
})();

That is all. Now you can run the app, go to the itemDetail, use the appbar command and print:

itemDetail Print

You can download the full example here.

Summary

In the post, I explained how to create print experience in a Windows Store app using the print contract. I also showed how to create your own source document. Adding contracts to Windows Store apps add value to your apps.

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

3 comments

  1. Sunny SinghJanuary 22, 2014 ב 14:28

    What if we want to print a PDF file with the same app?

    Reply
    1. Gil Fink
      Gil FinkJanuary 22, 2014 ב 15:16

      You can see a suggestion to print a PDF file in this Stack Overflow question: http://stackoverflow.com/questions/17533616/printing-pdf-documents-from-windows-8-app

      Reply
      1. Sunny SinghJanuary 23, 2014 ב 12:34

        Thank you so much.

        Reply