Как печатать файлы XPS программным способом

Можно использовать одну перегрузку метода AddJob для печати файлов XPS без открытия PrintDialog или любого пользовательского интерфейса (UI) в принципе.

Вы также можете выводить файлы XPS на печать с помощью множества методов XpsDocumentWriter.Write и XpsDocumentWriter.WriteAsync. Дополнительные сведения см. в документе Печать документа XPS.

Еще один способ печати XPS — использовать метод PrintDialog.PrintDocument или PrintDialog.PrintVisual. См. раздел Вызов диалогового окна печати.

Пример

Для использования метода AddJob(String, String, Boolean) с тремя параметрами применяются следующие действия. Подробные сведения см. в примере.

  1. Определите, является ли принтер принтером XPSDrv. (Дополнительные сведения о XPSDrv см. в разделе Обзор печати).

  2. Если принтер не является принтером XPSDrv, задайте однопотоковое подразделение потока.

  3. Создайте экземпляр сервера печати и объект очереди печати.

  4. Вызовите метод, указав имя задания, файл для печати и флаг Boolean, показывающий, будет ли принтер являться принтером XPSDrv.

В приведенном ниже примере показано, как выполнить пакетную печать всех файлов XPS в каталоге. Хотя приложение предлагает пользователю указать каталог, для метода AddJob(String, String, Boolean) с тремя параметрами не требуется пользовательский интерфейс. Его можно использовать в любом пути кода при условии, что вы знаете имя файла XPS и путь, который вы можете ему передать.

Перегрузка метода AddJob(String, String, Boolean) с тремя параметрами для AddJob должна выполняться в однопотоковом подразделении во всех случаях, когда параметр Boolean имеет значение false, которое он должен иметь, если используется принтер, отличный от XPSDrv. Однако по умолчанию состояние подразделения для .NET многопотоковое. Данное значение по умолчанию должно быть обращено, поскольку в этом примере предполагается, что принтер не является принтером XPSDrv.

Изменить значение по умолчанию можно одним из двух способов. Один из них — добавить STAThreadAttribute (т. е. «[System.STAThreadAttribute()]») непосредственно над первой строкой метода Main приложения (обычно это «static void Main(string[] args)»). Однако для многих приложений требуется, чтобы метод Main имел состояние многопотокового состояния, поэтому есть второй метод: поместите вызов в AddJob(String, String, Boolean) в отдельном потоке, состояние подразделения для которого установлено как STA с помощью SetApartmentState. В следующем примере используется второй метод.

Соответственно, пример начинается с создания экземпляра объекта Thread и передачи ему метода PrintXPS в качестве параметра ThreadStart. (The Метод PrintXPS определен позже в примере.) Далее для потока устанавливается одна квартира потока. Остальной код метода Main начинается с нового потока.

Основу этого примера составляет метод staticBatchXPSPrinter.PrintXPS. После создания сервера и очереди печати метод предлагает пользователю выбрать каталог, содержащий файлы XPS. После того, как существование каталога и наличие в нем XPS-файлов будет проверено, метод добавляет каждый такой файл в очередь печати. В контексте этого примера предполагается, что принтер не является принтером XPSDrv, поэтому мы передаем false в последний параметр метода AddJob(String, String, Boolean). В связи с этим метод проверит разметку XPS в файле и только после этого конвертирует его в язык описания страниц принтера. Если проверка завершается ошибкой, выдается исключение. Код в примере перехватит исключение, сообщит о нем пользователю, а затем перейдет к обработке следующего файла XPS.

class Program
{
    [System.MTAThreadAttribute()] // Added for clarity, but this line is redundant because MTA is the default.
    static void Main(string[] args)
    {
        // Create the secondary thread and pass the printing method for
        // the constructor's ThreadStart delegate parameter. The BatchXPSPrinter
        // class is defined below.
        Thread printingThread = new Thread(BatchXPSPrinter.PrintXPS);

        // Set the thread that will use PrintQueue.AddJob to single threading.
        printingThread.SetApartmentState(ApartmentState.STA);

        // Start the printing thread. The method passed to the Thread
        // constructor will execute.
        printingThread.Start();
    }//end Main
}//end Program class

public class BatchXPSPrinter
{
    public static void PrintXPS()
    {
        // Create print server and print queue.
        LocalPrintServer localPrintServer = new LocalPrintServer();
        PrintQueue defaultPrintQueue = LocalPrintServer.GetDefaultPrintQueue();

        // Prompt user to identify the directory, and then create the directory object.
        Console.Write("Enter the directory containing the XPS files: ");
        String directoryPath = Console.ReadLine();
        DirectoryInfo dir = new DirectoryInfo(directoryPath);

        // If the user mistyped, end the thread and return to the Main thread.
        if (!dir.Exists)
        {
            Console.WriteLine("There is no such directory.");
        }
        else
        {
            // If there are no XPS files in the directory, end the thread
            // and return to the Main thread.
            if (dir.GetFiles("*.xps").Length == 0)
            {
                Console.WriteLine("There are no XPS files in the directory.");
            }
            else
            {
                Console.WriteLine("\nJobs will now be added to the print queue.");
                Console.WriteLine("If the queue is not paused and the printer is working, jobs will begin printing.");

                // Batch process all XPS files in the directory.
                foreach (FileInfo f in dir.GetFiles("*.xps"))
                {
                    String nextFile = directoryPath + "\\" + f.Name;
                    Console.WriteLine("Adding {0} to queue.", nextFile);

                    try
                    {
                        // Print the Xps file while providing XPS validation and progress notifications.
                        PrintSystemJobInfo xpsPrintJob = defaultPrintQueue.AddJob(f.Name, nextFile, false);
                    }
                    catch (PrintJobException e)
                    {
                        Console.WriteLine("\n\t{0} could not be added to the print queue.", f.Name);
                        if (e.InnerException.Message == "File contains corrupted data.")
                        {
                            Console.WriteLine("\tIt is not a valid XPS file. Use the isXPS Conformance Tool to debug it.");
                        }
                        Console.WriteLine("\tContinuing with next XPS file.\n");
                    }
                }// end for each XPS file
            }//end if there are no XPS files in the directory
        }//end if the directory does not exist

        Console.WriteLine("Press Enter to end program.");
        Console.ReadLine();
    }// end PrintXPS method
}// end BatchXPSPrinter class
Friend Class Program
    <System.MTAThreadAttribute()>
    Shared Sub Main(ByVal args() As String) ' Added for clarity, but this line is redundant because MTA is the default.
        ' Create the secondary thread and pass the printing method for 
        ' the constructor's ThreadStart delegate parameter. The BatchXPSPrinter
        ' class is defined below.
        Dim printingThread As New Thread(AddressOf BatchXPSPrinter.PrintXPS)

        ' Set the thread that will use PrintQueue.AddJob to single threading.
        printingThread.SetApartmentState(ApartmentState.STA)

        ' Start the printing thread. The method passed to the Thread 
        ' constructor will execute.
        printingThread.Start()

    End Sub

End Class

Public Class BatchXPSPrinter
    Public Shared Sub PrintXPS()
        ' Create print server and print queue.
        Dim localPrintServer As New LocalPrintServer()
        Dim defaultPrintQueue As PrintQueue = LocalPrintServer.GetDefaultPrintQueue()

        ' Prompt user to identify the directory, and then create the directory object.
        Console.Write("Enter the directory containing the XPS files: ")
        Dim directoryPath As String = Console.ReadLine()
        Dim dir As New DirectoryInfo(directoryPath)

        ' If the user mistyped, end the thread and return to the Main thread.
        If Not dir.Exists Then
            Console.WriteLine("There is no such directory.")
        Else
            ' If there are no XPS files in the directory, end the thread 
            ' and return to the Main thread.
            If dir.GetFiles("*.xps").Length = 0 Then
                Console.WriteLine("There are no XPS files in the directory.")
            Else
                Console.WriteLine(vbLf & "Jobs will now be added to the print queue.")
                Console.WriteLine("If the queue is not paused and the printer is working, jobs will begin printing.")

                ' Batch process all XPS files in the directory.
                For Each f As FileInfo In dir.GetFiles("*.xps")
                    Dim nextFile As String = directoryPath & "\" & f.Name
                    Console.WriteLine("Adding {0} to queue.", nextFile)

                    Try
                        ' Print the Xps file while providing XPS validation and progress notifications.
                        Dim xpsPrintJob As PrintSystemJobInfo = defaultPrintQueue.AddJob(f.Name, nextFile, False)
                    Catch e As PrintJobException
                        Console.WriteLine(vbLf & vbTab & "{0} could not be added to the print queue.", f.Name)
                        If e.InnerException.Message = "File contains corrupted data." Then
                            Console.WriteLine(vbTab & "It is not a valid XPS file. Use the isXPS Conformance Tool to debug it.")
                        End If
                        Console.WriteLine(vbTab & "Continuing with next XPS file." & vbLf)
                    End Try

                Next f ' end for each XPS file

            End If 'end if there are no XPS files in the directory

        End If 'end if the directory does not exist

        Console.WriteLine("Press Enter to end program.")
        Console.ReadLine()

    End Sub

End Class

Если вы используете принтер XPSDrv, последнему параметру можно присвоить значение true. В этом случае, поскольку XPS является языком описания страниц принтера, метод отправляет файл на принтер без проверки или преобразования в другой язык описания страниц. Если во время разработки вы не уверены, будет ли приложение использовать принтер XPSDrv, вы можете изменить приложение таким образом, чтобы оно читало свойство IsXpsDevice и выполняло соответствующие переходы.

Поскольку сразу после выпуска Windows Vista и Microsoft .NET Framework будут доступны всего несколько принтеров XSPSDrv, принтер, который не является принтером XPSDrv, можно замаскировать. Для этого добавьте файл Pipelineconfig.xml в список файлов в следующем разделе реестра компьютера, на котором выполняется ваше приложение:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Environments\Windows NT x86\Drivers\Version-3<PseudoXPSPrinter>\DependentFiles

где <PseudoXPSPrinter> — это любая очередь печати. После этого компьютер необходимо перезагрузить.

Эта маскировка позволит вам передать true как последний параметр AddJob(String, String, Boolean), не вызывая исключение, однако, в связи с тем, что <PseudoXPSPrinter> по сути не является принтером XPSDrv, будет распечатан только мусор.

Примечание.

Для простоты в приведенном выше примере то, является ли файл XPS-файлом, проверяется по наличию расширения XPS. При этом файлы XPS не обязательно должны иметь такое расширение. isXPS.exe (isXPS Conformance Tool) является одним из способов проверки файла на соответствие XPS.

См. также