共用方式為


HOW TO:以程式設計方式列印 XPS 檔

您可以使用 AddJob 方法的其中一個多載來列印 XML Paper Specification (XPS) 檔案,而不需要開啟 PrintDialog,原則上根本也不需要開啟任何user interface (UI)。

也可以使用 XpsDocumentWriter 的許多 WriteWriteAsync 方法,來列印 XML Paper Specification (XPS) 檔案。 如需此方面的詳細資訊,請參閱Printing an XPS Document

另一種列印 XML Paper Specification (XPS) 的方式是使用 PrintDialog 控制項的 PrintDocumentPrintVisual 方法。 請參閱 HOW TO:叫用列印對話方塊

範例

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

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

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

  3. 具現化 (Instantiate) 列印伺服器和列印佇列物件。

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

下面的範例顯示如何將目錄中的所有 XPS 檔案進行批次列印。 雖然應用程式會提示使用者指定目錄,但是由三個參數組成的 AddJob(String, String, Boolean) 方法並不需要user interface (UI)。 它可以用於任何具有 XPS 檔案名稱的程式碼路徑,以及可以\存取的路徑。

Boolean 參數是 false 時 (使用非 XPSDrv 印表機時必須為此值),AddJob 之由三個參數組成的 AddJob(String, String, Boolean) 多載就必須在單一執行緒 Apartment 中執行。 然而,Microsoft .NET 的預設 Apartment 狀態是多執行緒。 因為範例假設的是非 XPSDrv 印表機,所以必須改變這個預設值。

變更預設值的方式有兩種。 其中一種方式只要將 STAThreadAttribute (即 "[System.STAThreadAttribute()]") 加入至應用程式之 Main 方法的第一行上方 (通常是 "static void Main(string[] args)")。 然而,許多應用程式還需要 Main 方法具有多執行緒 Apartment 狀態,因此另有第二種方法:在不同執行緒中進行 AddJob(String, String, Boolean) 的呼叫,這個執行緒的 Apartment 狀態是使用 SetApartmentState 設為 STA。 下面範例使用的是第二種技術。

因此,範例一開始是具現化 Thread 物件,並將 PrintXPS 方法傳遞給它做為 ThreadStart 參數 (PrintXPS 方法稍後將於範例中定義)。接下來,將執行緒設為單一執行緒 Apartment。 而 Main 方法中唯一餘下的程式碼會啟動新的執行緒。

範例的主要部分是 static BatchXPSPrinter.PrintXPS 方法。 建立列印伺服器和佇列之後,方法會提示使用者輸入含有 XPS 檔案的目錄。 而在驗證目錄及其內的 *.xps 檔案確實存在之後,方法會將每個這類檔案加入至列印佇列。 範例假設印表機是非 XPSDrv,所以會將 false 傳遞給 AddJob(String, String, Boolean) 方法的最後一個參數。 因此,方法會先驗證檔案中的 XPS 標記,再嘗試將它轉換為印表機的頁面描述語言。 如果驗證失敗,則會擲回例外狀況。 而範例程式碼會攔截例外狀況、通知使用者發生例外狀況,然後繼續處理下一個 XPS 檔案。

    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 Main

    End Class 'end Program 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 PrintXPS method

    End Class ' end BatchXPSPrinter class
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

如果使用的是 XPSDrv 印表機,則可以將最終參數設為 true。 在該情況下,因為 XPS 是印表機的頁面描述語言,所以方法會將檔案傳送給印表機,而不需要進行驗證,或將它轉換為另一種頁面描述語言。 如果在設計階段不確定應用程式是否使用 XPSDrv 印表機,則可以修改應用程式,讓它根據找到的內容讀取 IsXpsDevice 屬性作判斷。

因為一開始在發行 Windows Vista 和 Microsoft .NET Framework 之後立即可用的 XPSDrv 印表機很少,所以可能需要將非 XPSDrv 印表機偽裝成 XPSDrv 印表機。 若要執行此作業,請在執行應用程式之電腦的下列登錄機碼 (Registry Key) 中,將 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 有效性的一種方式。

請參閱

工作

Printing an XPS Document

參考

PrintQueue

AddJob

ApartmentState

STAThreadAttribute

概念

Managed 和 Unmanaged 執行緒處理

isXPS.exe (isXPS 一致性工具)

WPF 中的文件

列印概觀

其他資源

XPS