How to print an XPS file (WPF .NET)

Sometimes you'll want to add a new print job to the print queue without opening a print dialog box. You can use one of the PrintQueue.AddJob methods to do that. Here's how.

In the following example, we use the AddJob(String, String, Boolean) method, one of the several overloads of AddJob, to:

  • Add a new print job for an XML Paper Specification (XPS) document into the default print queue.
  • Name the new job.
  • Specify whether the XPS document should be validated (by using the fastCopy parameter).

When using the AddJob(String, String, Boolean) method, the value of the fastCopy parameter is a key consideration:

  • If you set the fastCopy parameter to true, then XPS validation is skipped and the print job will spool quickly without page-by-page progress feedback.
  • If you set the fastCopy parameter to false, then the thread that calls the AddJob method must have a single-threaded apartment state, otherwise an exception will be thrown. For more information, see the Remarks section for AddJob(String, String, Boolean).

Add new print jobs to the queue

This example adds one or more XPS documents to the default queue. The code will:

  1. Use Task.Run to avoid blocking the UI thread—since there's no async version of AddJob.
  2. If the fastCopy parameter value is false, run AddJob(String, String, Boolean) on a thread with single-threaded apartment state.
  3. Get a reference to the default PrintQueue of the LocalPrintServer.
  4. Call AddJob(String, String, Boolean) on the print queue reference, passing in a job name, an XPS document path, and the fastCopy parameter.

If the queue isn't paused and the printer is working, then a print job will automatically begin printing when it reaches the top of the print queue.

Tip

To avoid the Save Output File As dialog when adding a print job to the default queue, ensure that your default printer isn't Microsoft XPS Document Writer, Microsoft Print to PDF, or other print-to-file options.

/// <summary>
/// Asyncronously, add a batch of XPS documents to the print queue using a PrintQueue.AddJob method.
/// Handle the thread apartment state required by the PrintQueue.AddJob method.
/// </summary>
/// <param name="xpsFilePaths">A collection of XPS documents.</param>
/// <param name="fastCopy">Whether to validate the XPS documents.</param>
/// <returns>Whether all documents were added to the print queue.</returns>
public static async Task<bool> BatchAddToPrintQueueAsync(IEnumerable<string> xpsFilePaths, bool fastCopy = false)
{
    bool allAdded = true;

    // Queue some work to run on the ThreadPool.
    // Wait for completion without blocking the calling thread.
    await Task.Run(() =>
    {
        if (fastCopy)
            allAdded = BatchAddToPrintQueue(xpsFilePaths, fastCopy);
        else
        {
            // Create a thread to call the PrintQueue.AddJob method.
            Thread newThread = new(() =>
            {
                allAdded = BatchAddToPrintQueue(xpsFilePaths, fastCopy);
            });

            // Set the thread to single-threaded apartment state.
            newThread.SetApartmentState(ApartmentState.STA);

            // Start the thread.
            newThread.Start();

            // Wait for thread completion. Blocks the calling thread,
            // which is a ThreadPool thread.
            newThread.Join();
        }
    });

    return allAdded;
}

/// <summary>
/// Add a batch of XPS documents to the print queue using a PrintQueue.AddJob method.
/// </summary>
/// <param name="xpsFilePaths">A collection of XPS documents.</param>
/// <param name="fastCopy">Whether to validate the XPS documents.</param>
/// <returns>Whether all documents were added to the print queue.</returns>
public static bool BatchAddToPrintQueue(IEnumerable<string> xpsFilePaths, bool fastCopy)
{
    bool allAdded = true;

    // To print without getting the "Save Output File As" dialog, ensure
    // that your default printer is not the Microsoft XPS Document Writer,
    // Microsoft Print to PDF, or other print-to-file option.

    // Get a reference to the default print queue.
    PrintQueue defaultPrintQueue = LocalPrintServer.GetDefaultPrintQueue();

    // Iterate through the document collection.
    foreach (string xpsFilePath in xpsFilePaths)
    {
        // Get document name.
        string xpsFileName = Path.GetFileName(xpsFilePath);

        try
        {
            // The AddJob method adds a new print job for an XPS
            // document into the print queue, and assigns a job name.
            // Use fastCopy to skip XPS validation and progress notifications.
            // If fastCopy is false, the thread that calls PrintQueue.AddJob
            // must have a single-threaded apartment state.
            PrintSystemJobInfo xpsPrintJob =
                    defaultPrintQueue.AddJob(jobName: xpsFileName, documentPath: xpsFilePath, fastCopy);

            // If the queue is not paused and the printer is working, then jobs will automatically begin printing.
            Debug.WriteLine($"Added {xpsFileName} to the print queue.");
        }
        catch (PrintJobException e)
        {
            allAdded = false;
            Debug.WriteLine($"Failed to add {xpsFileName} to the print queue: {e.Message}\r\n{e.InnerException}");
        }
    }

    return allAdded;
}
''' <summary>
''' Asyncronously, add a batch of XPS documents to the print queue using a PrintQueue.AddJob method.
''' Handle the thread apartment state required by the PrintQueue.AddJob method.
''' </summary>
''' <param name="xpsFilePaths">A collection of XPS documents.</param>
''' <param name="fastCopy">Whether to validate the XPS documents.</param>
''' <returns>Whether all documents were added to the print queue.</returns>
Public Shared Async Function BatchAddToPrintQueueAsync(xpsFilePaths As IEnumerable(Of String), Optional fastCopy As Boolean = False) As Task(Of Boolean)

    Dim isAllPrinted As Boolean = True

    ' Queue some work to run on the ThreadPool.
    ' Wait for completion without blocking the calling thread.
    Await Task.Run(
        Sub()
            If fastCopy Then
                isAllPrinted = BatchAddToPrintQueue(xpsFilePaths, fastCopy)
            Else
                ' Create a thread to call the PrintQueue.AddJob method.
                Dim newThread As New Thread(
                    Sub()
                        isAllPrinted = BatchAddToPrintQueue(xpsFilePaths, fastCopy)
                    End Sub
                )

                ' Set the thread to single-threaded apartment state.
                newThread.SetApartmentState(ApartmentState.STA)

                ' Start the thread.
                newThread.Start()

                ' Wait for thread completion. Blocks the calling thread,
                ' which is a ThreadPool thread.
                newThread.Join()
            End If
        End Sub
    )

    Return isAllPrinted

End Function

''' <summary>
''' Add a batch of XPS documents to the print queue using a PrintQueue.AddJob method.
''' </summary>
''' <param name="xpsFilePaths">A collection of XPS documents.</param>
''' <param name="fastCopy">Whether to validate the XPS documents.</param>
''' <returns>Whether all documents were added to the print queue.</returns>
Public Shared Function BatchAddToPrintQueue(xpsFilePaths As IEnumerable(Of String), fastCopy As Boolean) As Boolean

    Dim isAllPrinted As Boolean = True

    ' To print without getting the "Save Output File As" dialog, ensure
    ' that your default printer is not the Microsoft XPS Document Writer,
    ' Microsoft Print to PDF, or other print-to-file option.

    ' Get a reference to the default print queue.
    Dim defaultPrintQueue As PrintQueue = LocalPrintServer.GetDefaultPrintQueue()

    ' Iterate through the document collection.
    For Each xpsFilePath As String In xpsFilePaths

        ' Get document name.
        Dim xpsFileName As String = Path.GetFileName(xpsFilePath)

        Try
            ' The AddJob method adds a new print job for an XPS
            ' document into the print queue, and assigns a job name.
            ' Use fastCopy to skip XPS validation and progress notifications.
            ' If fastCopy is false, the thread that calls PrintQueue.AddJob
            ' must have a single-threaded apartment state.
            Dim xpsPrintJob As PrintSystemJobInfo = defaultPrintQueue.AddJob(jobName:=xpsFileName, documentPath:=xpsFilePath, fastCopy)

            ' If the queue is not paused and the printer is working, then jobs will automatically begin printing.
            Debug.WriteLine($"Added {xpsFileName} to the print queue.")
        Catch e As PrintJobException
            isAllPrinted = False
            Debug.WriteLine($"Failed to add {xpsFileName} to the print queue: {e.Message}\r\n{e.InnerException}")
        End Try
    Next

    Return isAllPrinted

End Function

Tip

You can also print XPS files by using:

For more information, see How to display a print dialog box and Printing documents overview.

See also