共用方式為


如何:以程式設計方式列印 XPS 檔

您可以使用 AddJob 方法的一個多載來列印 XML 文件規格 (XPS) 檔案,而不需開啟 PrintDialog 或任何使用者介面 (UI)。

您也可以使用許多 XpsDocumentWriter.WriteXpsDocumentWriter.WriteAsync 方法來列印 XPS 檔案。 如需詳細資訊,請參閱列印 XPS 文件

列印 XPS 的另一種方式是使用 PrintDialog.PrintDocumentPrintDialog.PrintVisual 方法。 請參閱叫用列印對話方塊

範例

使用三個參數 AddJob(String, String, Boolean) 方法的主要步驟如下。 下列範例會提供詳細資料。

  1. 判斷印表機是否為 XPSDrv 印表機。 如需 XPSDrv 的詳細資訊,請參閱列印概觀

  2. 如果印表機不是 XPSDrv 印表機,將執行緒的 Apartment 設定為單一執行緒。

  3. 將列印伺服器與列印佇列物件具現化。

  4. 呼叫此方法,並指定工作名稱、要列印的檔案以及 Boolean 旗標,而該旗標可指出印表機是否為 XPSDrv 印表機。

下列範例示範如何批次列印目錄中的所有 XPS 檔案。 雖然應用程式會提示使用者指定目錄,但三個參數 AddJob(String, String, Boolean) 方法不需要使用者介面 (UI)。 它可以使用於任何程式碼路徑,其中包含您可以傳遞至的 XPS 檔案名稱和路徑。

AddJob 的三個參數 AddJob(String, String, Boolean) 多載必須在單一執行緒 Apartment 中執行,每當 Boolean 參數是 false,就一定是使用非 XPSDrv 印表機的時候。 不過,.NET 的預設 Apartment 狀態為多執行緒。 必須還原此預設值,因為此範例採用非 XPSDrv 印表機。

變更預設值的方式有兩種。 其中一種方式只要在應用程式的 Main 方法 (通常為「static void Main(string[] args)」) 第一行正上方新增 STAThreadAttribute (也就是「[System.STAThreadAttribute()]」)。 不過,許多應用程式要求 Main 方法具有多執行緒 Apartment 狀態,因此有第二個方法:將呼叫放在個別執行緒的 AddJob(String, String, Boolean) 中,其 Apartment 狀態設定為 STA 搭配 SetApartmentState。 下列範例使用此第二種技術。

因此,此範例的開頭是具現化 Thread 物件,並將 printXPS 方法當做 ThreadStart 參數傳遞給該物件。 (PrintXPS 方法稍後會定義在範例中。)接下來執行緒會設定為單一執行緒 Apartment。 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 發行後會有幾部 XPSDrv 印表機立即可用,所以您可能需要將非 XPSDrv 印表機偽裝成 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 一致性工具) 是一種測試檔案之 XPS 有效性的方法。

另請參閱