Gewusst wie: Programmgesteuertes Drucken von XPS-Dateien

Sie können eine Überladung der AddJob-Methode verwenden, um XPS-Dateien (XML Paper Specification) zu drucken, ohne einen PrintDialog oder im Prinzip überhaupt eine Benutzeroberfläche (UI) zu öffnen.

Sie können XPS-Dateien auch mit den vielen XpsDocumentWriter.Write- und XpsDocumentWriter.WriteAsync-Methoden drucken. Weitere Informationen finden Sie unter Drucken eines XPS-Dokuments.

Eine weitere Möglichkeit zum Drucken von XPS-Dateien ist die Verwendung der Methoden PrintDialog.PrintDocument oder PrintDialog.PrintVisual. Weitere Informationen finden Sie unter Aufrufen eines Druckdialogfelds.

Beispiel

Die wichtigsten Schritte bei der Anwendung der 3-Parameter-Methode AddJob(String, String, Boolean) werden im Folgenden beschrieben. Details finden Sie im nachstehenden Beispiel.

  1. Stellen Sie fest, ob es sich bei dem Drucker um einen XPSDrv-Drucker handelt. Weitere Informationen zu XPSDrv finden Sie unter Übersicht über das Drucken.

  2. Wenn es sich bei dem Drucker nicht um einen XPSDrv-Drucker handelt, legen Sie das Apartment des Threads auf Singlethread fest.

  3. Instanziieren Sie einen Druckerserver und ein Druckwarteschlangenobjekt.

  4. Rufen Sie die Methode auf, und geben Sie einen Auftragsnamen, die zu druckende Datei und ein Boolean-Flag an. Dieses Flag gibt an, ob es sich um einen XPSDrv-Drucker handelt oder nicht.

Das nachstehende Beispiel zeigt, wie Sie alle XPS-Dateien in einem Verzeichnis im Batch drucken können. Obwohl die Anwendung den Benutzer auffordert, das Verzeichnis anzugeben, ist für die 3-Parameter-Methode AddJob(String, String, Boolean) keine Benutzeroberfläche (UI) erforderlich. Sie kann in jedem Codepfad verwendet werden, in dem ein XPS-Dateiname vorhanden sind, der an die Methode übergeben werden können.

Die 3-Parameter-Überladung AddJob(String, String, Boolean) von AddJob muss in einem Singlethread-Apartment ausgeführt werden, wenn der Parameter Boolean den Wert false aufweist. Dies ist zwingend der Fall, wenn ein Nicht-XPSDrv-Drucker verwendet wird. Standardmäßig wird für .NET jedoch ein Multithread-Apartment verwendet. Dieser Standard muss umgekehrt werden, da im Beispiel kein XPSDrv-Drucker angenommen wird.

Es gibt zwei Möglichkeiten, die Standardeinstellung zu ändern. Eine Möglichkeit besteht darin, das STAThreadAttribute (d. h. [System.STAThreadAttribute()]) direkt über der ersten Zeile der Main-Methode der Anwendung (normalerweise static void Main(string[] args)) einzufügen. Viele Anwendungen erfordern jedoch, dass die Main-Methode einen Multithread-Apartmentstatus aufweist. Daher gibt es eine zweite Methode: Platzieren Sie den Aufruf von AddJob(String, String, Boolean) in einem separaten Thread, dessen Apartmentstatus auf STA mit SetApartmentState festgelegt ist. Im folgenden Beispiel wird dieses zweite Verfahren verwendet.

Dementsprechend beginnt das Beispiel mit der Instanziierung eines Thread-Objekts und der Übergabe einer PrintXPS-Methode als ThreadStart-Parameter. (Die PrintXPS-Methode wird später im Beispiel definiert.) Danach wird der Thread auf ein Singlethreadapartment festgelegt. Mit dem verbleibenden Code der Main-Methode wird der neue Thread gestartet.

In diesem Beispiel geht es im Wesentlichen um die staticBatchXPSPrinter.PrintXPS-Methode. Nach dem Erstellen eines Druckerservers und einer Druckwarteschlange wird der Benutzer von der Methode aufgefordert, ein Verzeichnis anzugeben, das XPS-Dateien enthält. Nachdem überprüft wurde, ob das Verzeichnis vorhanden ist und XPS-Dateien enthält, fügt die Methode jede dieser Dateien der Druckwarteschlange hinzu. Im Beispiel wird davon ausgegangen, dass es sich um einen Nicht-XPSDrv-Drucker handelt, also übergeben wir false an den letzten Parameter der Methode AddJob(String, String, Boolean). Aus diesem Grund überprüft die Methode das XPS-Markup in der Datei, bevor sie versucht, eine Konvertierung in die Seitenbeschreibungssprache des Druckers vorzunehmen. Wenn die Validierung fehlschlägt, wird eine Ausnahme ausgelöst. Im Beispielcode wird die Ausnahme abgefangen, der Benutzer wird darüber informiert, und anschließend wird die nächste XPS-Datei verarbeitet.

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

Wenn Sie einen XPSDrv-Drucker verwenden, können Sie den abschließenden Parameter auf true festlegen. Da in diesem Fall XPS die Seitenbeschreibungssprache des Druckers ist, sendet die Methode die Datei an den Drucker, ohne sie zu überprüfen oder sie in eine andere Seitenbeschreibungssprache zu konvertieren. Wenn Sie zur Entwurfszeit nicht sicher sind, ob die Anwendung einen XPSDrv-Drucker verwenden wird, können Sie die Anwendung so ändern, dass sie die Eigenschaft IsXpsDevice liest und je nach Ergebnis verzweigt.

Da unmittelbar nach der Veröffentlichung von Windows Vista und Microsoft .NET Framework zunächst nur wenige XPSDrv-Drucker verfügbar sein werden, müssen Sie Nicht-XPSDrv-Drucker ggf. als XPSDrv-Drucker tarnen. Fügen Sie hierzu auf dem Computer, der die Anwendung ausführt, im folgenden Registrierungsschlüssel die Datei „Pipelineconfig.xml“ zur Liste der Dateien hinzu:

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

Hierbei steht <PseudoXPSPrinter> für eine beliebige Druckwarteschlange. Der Computer muss anschließend neu gestartet werden.

Mithilfe dieser Tarnung können Sie true als letzten Parameter von AddJob(String, String, Boolean) übergeben, ohne eine Ausnahme auszulösen. Da es sich bei <PseudoXPSPrinter> aber nicht wirklich um einen XPSDrv-Drucker handelt, erhalten Sie keine ordnungsgemäße Druckausgabe.

Hinweis

Der Einfachheit halber gilt im oben stehenden Beispiel das Vorhandensein der Dateinamenserweiterung XPS als Beleg dafür, dass es sich bei einer Datei um eine XPS-Datei handelt. XPS-Dateien müssen jedoch nicht diese Erweiterung aufweisen. Sie können die XPS-Gültigkeit einer Datei beispielsweise mit isXPS.exe (isXPS Conformance Tool) testen.

Weitere Informationen