如何在 UWP 裝置應用程式中管理列印作業

在 Windows 8.1 中,適用於印表機的 UWP 裝置應用程式可以管理列印作業。 本主題使用列印作業管理和印表機維護範例的 C# 版本,示範如何建立列印作業的檢視、監視這些作業,以及在必要時取消作業。 若要深入瞭解一般 UWP 裝置應用程式,請參閱 滿足 UWP 裝置應用程式

印表作業管理和印表機維護範例的 C# 版本示範使用 DeviceAppForPrinters2 專案中DeviceMaintenance.xaml.cs檔案的印表機維護。 若要使用 Bidi,此範例會使用 PrinterExtensionLibrary 專案中的印表機延伸模組連結庫。 印表機延伸模組連結庫提供方便的方式來存取 v4 印表驅動程式的印表機延伸模組介面。 如需詳細資訊,請參閱 印表機擴充功能庫概觀

本主題中顯示的程式代碼範例是以列印作業管理和印表機維護範例的 C# 版本為基礎。 此範例也適用於 JavaScript 和 C++。 請注意,因為 C++ 可以直接存取 COM,因此範例的 C++ 版本不包含程式碼庫專案。 下載範例以查看最新版本的程序代碼。

管理列印作業

Windows 8.1 會在 v4 印表機驅動程式中引進新的印表機延伸模組介面,可用來管理列印作業:IPrinterQueue2、IPrinterQueueView、IPrinterQueueViewEventIPrintJob IPrintJobCollection。 這些介面可讓您監視和取消列印作業。 如需詳細資訊,請參閱列印作業管理(v4 印表機驅動程式)。

C# 和 JavaScript 應用程式無法直接使用 COM API。 如果您要撰寫 C# 或 JavaScript UWP 裝置應用程式,請使用印表機延伸模組連結庫來存取這些介面(如本主題所示)。

必要條件

開始之前:

  1. 請確定您的印表機是使用 v4 印表驅動程式安裝。 如需詳細資訊,請參閱 開發 v4 列印驅動程式

  2. 設定您的開發電腦。 如需下載工具及建立開發人員帳戶的相關信息,請參閱 開始使用

  3. 將您的應用程式與市集產生關聯。 如需相關信息,請參閱 建立UWP裝置應用程式

  4. 為您的印表機建立裝置元數據,使其與您的應用程式產生關聯。 如需詳細資訊,請參閱 建立裝置元數據

  5. 建置應用程式主頁面的UI。 所有UWP裝置應用程式都可以從 [開始] 啟動,其中會顯示全螢幕。 使用 \[開始\] 體驗,以符合您裝置的特定品牌和功能的方式反白顯示您的產品或服務。 它可以使用的UI控制件類型沒有任何特殊限制。 若要開始使用全螢幕體驗的設計,請參閱 Microsoft Store 設計原則

  6. 如果您要撰寫使用 C# 或 JavaScript 撰寫應用程式,請將 PrinterExtensionLibrary 專案新增至 UWP 裝置應用程式解決方案。 您可以在列印作業管理和印表機維護範例中找到此專案。

因為 C++ 可以直接存取 COM,C++ 應用程式不需要個別的連結庫才能使用以 COM 為基礎的印表機裝置內容。

步驟 1:尋找印表機

在您的應用程式可以管理列印作業之前,必須先找出具有列印作業的印表機。 若要這樣做,列印作業管理和印表機維護範例會包含名為 PrinterEnumeration 的方便類別(在 PrinterEnumeration.cs 檔案中)。 這個類別會尋找透過裝置元數據與應用程式相關聯的所有印表機,並傳回物件清單 PrinterInfo ,其中包含每個印表機的名稱和裝置識別符。

這個範例顯示 EnumeratePrinters_Click PrintJobManagement.xaml.cs 檔案中的方法。 它示範範例 PrinterEnumeration 如何使用 類別來取得相關聯的印表機清單。

private async void EnumeratePrinters_Click(object sender, RoutedEventArgs e)
{
    try
    {
        rootPage.NotifyUser("Enumerating printers. Please wait", NotifyType.StatusMessage);

        // Retrieve the running app's package family name, and enumerate associated printers.
        string currentPackageFamilyName = Windows.ApplicationModel.Package.Current.Id.FamilyName;

        // Enumerate associated printers.
        PrinterEnumeration pe = new PrinterEnumeration(currentPackageFamilyName);
        List<PrinterInfo> associatedPrinters = await pe.EnumeratePrintersAsync();

        // Update the data binding source on the combo box that displays the list of printers.
        PrinterComboBox.ItemsSource = associatedPrinters;
        if (associatedPrinters.Count > 0)
        {
            PrinterComboBox.SelectedIndex = 0;
            rootPage.NotifyUser(associatedPrinters.Count + " printers enumerated", NotifyType.StatusMessage);
        }
        else
        {
            rootPage.NotifyUser(DisplayStrings.NoPrintersEnumerated, NotifyType.ErrorMessage);
        }
    }
    catch (Exception exception)
    {
        rootPage.NotifyUser("Caught an exception: " + exception.Message, NotifyType.ErrorMessage);
    }
}

如需 和類別的詳細資訊PrinterEnumeration,請參閱 PrinterEnumeration.cs 檔案。PrinterInfo

步驟 2:取得印表機佇列

一旦您識別出印表機具有您想要管理的列印作業,請根據介面建立列印作業的檢視,並依據 介面來建立物件(定義IPrinterQueueViewPrinterExtensionLibrary 專案的PrinterExtensionTypes.cs檔案中)。[列印作業管理和印表機維護 範例] 中,此物件會命名 currentPrinterQueueView 為 ,而且會在每次印表機選取範圍變更時重新建立。

在方法中 Printer_SelectionChanged ,範例會先使用 PrinterInfo 物件來建立名為 的 context印表機延伸內容物件。 然後它會使用 GetPrinterQueueView 上的 context 方法來建立 currentPrinterQueueView 物件。 最後,會新增事件處理程序來處理 currentPrinterQueueViewOnChanged 事件。

這個範例顯示 Printer_SelectionChanged PrintJobManagement.xaml.cs 檔案中的方法。 它示範如何根據 IPrinterQueueView建立印表機佇列檢視物件。

private void Printer_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    try
    {
        // Remove the current printer queue view (if any) before displaying the new view.
        if (currentPrinterQueueView != null)
        {
            currentPrinterQueueView.OnChanged -= OnPrinterQueueViewChanged;
            currentPrinterQueueView = null;
        }

        // Retrieve a COM IPrinterExtensionContext object, using the static WinRT factory.
        // Then instantiate one "PrinterExtensionContext" object that allows operations on the COM object.
        PrinterInfo queue = (PrinterInfo)PrinterComboBox.SelectedItem;
        Object comContext = Windows.Devices.Printers.Extensions.PrintExtensionContext.FromDeviceId(queue.DeviceId);
        PrinterExtensionContext context = new PrinterExtensionContext(comContext);

        // Display the printer queue view.
        const int FirstPrintJobEnumerated = 0;
        const int LastPrintJobEnumerated = 10;

        currentPrinterQueueView = context.Queue.GetPrinterQueueView(FirstPrintJobEnumerated, LastPrintJobEnumerated);
        currentPrinterQueueView.OnChanged += OnPrinterQueueViewChanged;
    }
    catch (Exception exception)
    {
        rootPage.NotifyUser("Caught an exception: " + exception.Message, NotifyType.ErrorMessage);
    }
}

此外,每當列印作業的檢視有所變更時,事件處理程式就會呼叫 OnPrinterQueueViewChanged 方法。 此方法負責使用 物件的 IEnumerable 集合IPrintJob重新繫結 PrintJobListBox 。 集合會透過 PrinterQueueViewEventArgs 對象傳遞至 方法,該物件定義於 PrinterExtensionTypes.cs 檔案中

這個範例顯示 OnPrinterQueueViewChanged PrintJobManagement.xaml.cs 檔案中的方法。

private async void OnPrinterQueueViewChanged(object sender, PrinterQueueViewEventArgs e)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        // Update the data binding on the ListBox that displays print jobs.
        PrintJobListBox.ItemsSource = e.Collection;
        if (PrintJobListBox.Items.Count > 0)
        {
            // If there are print jobs in the current view, mark the first job as selected.
            PrintJobListBox.SelectedIndex = 0;
        }
    });
}

步驟 3:顯示列印作業狀態

PrintJobListBox由於 系結至 物件的集合IPrintJob,因此顯示作業的狀態相當簡單。 選取的列印作業會轉換成 IPrintJob 物件,然後使用該對象的屬性來填滿 PrintJobDetails TextBox。

在列印 作業管理和印表機維護 範例中,每次選取不同的列印作業時,就會顯示列印作業狀態。 此方法會處理 PrintJob_SelectionChanged 此更新。

這個範例顯示 PrintJob_SelectionChanged PrintJobManagement.xaml.cs 檔案中的方法。 它顯示如何根據 IPrintJob 對象顯示列印作業的狀態。

private void PrintJob_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    try
    {
        // Display details of the selected print job.
        IPrintJob job = (IPrintJob)PrintJobListBox.SelectedItem;
        if (job != null)
        {
            PrintJobDetails.Text =
                "Details of print job: " + job.Name + "\r\n" +
                "Pages printed: " + job.PrintedPages + "/" + job.TotalPages + "\r\n" +
                "Submission time: " + job.SubmissionTime + "\r\n" +
                "Job status: " + DisplayablePrintJobStatus.ToString(job.Status);
        }
        else
        {
            PrintJobDetails.Text = "Please select a print job";
        }
    }
    catch (Exception exception)
    {
        rootPage.NotifyUser("Caught an exception: " + exception.Message, NotifyType.ErrorMessage);
    }
}

為了協助顯示列印作業狀態描述, PrintJob_SelectionChanged 此方法會使用名為 printJobStatusDisplayNames的靜態字典,協助顯示使用者易記文字格式的作業狀態描述。

此範例顯示 DisplayablePrintJobStatus PrintJobManagement.xaml.cs 檔案中的 類別。 這個類別包含 所使用的 PrintJob_SelectionChanged靜態成員。

internal class DisplayablePrintJobStatus
{
    /// <summary>
    /// Converts the PrintJobStatus bit fields to a display string.
    /// </summary>
    internal static string ToString(PrintJobStatus printJobStatus)
    {
        StringBuilder statusString = new StringBuilder();

        // Iterate through each of the PrintJobStatus bits that are set and convert it to a display string.
        foreach (var printJobStatusDisplayName in printJobStatusDisplayNames)
        {
            if ((printJobStatusDisplayName.Key & printJobStatus) != 0)
            {
                statusString.Append(printJobStatusDisplayName.Value);
            }
        }

        int stringlen = statusString.Length;
        if (stringlen > 0)
        {
            // Trim the trailing comma from the string.
            return statusString.ToString(0, stringlen - 1);
        }
        else
        {
            // If no print job status field was set, display "Not available".
            return "Not available";
        }
    }

    /// <summary>
    /// Static constructor that initializes the display name for the PrintJobStatus field.
    /// </summary>
    static DisplayablePrintJobStatus()
    {
        printJobStatusDisplayNames = new Dictionary<PrintJobStatus, string>();

        printJobStatusDisplayNames.Add(PrintJobStatus.Paused, "Paused,");
        printJobStatusDisplayNames.Add(PrintJobStatus.Error, "Error,");
        printJobStatusDisplayNames.Add(PrintJobStatus.Deleting, "Deleting,");
        printJobStatusDisplayNames.Add(PrintJobStatus.Spooling, "Spooling,");
        printJobStatusDisplayNames.Add(PrintJobStatus.Printing, "Printing,");
        printJobStatusDisplayNames.Add(PrintJobStatus.Offline, "Offline,");
        printJobStatusDisplayNames.Add(PrintJobStatus.PaperOut, "Out of paper,");
        printJobStatusDisplayNames.Add(PrintJobStatus.Printed, "Printed,");
        printJobStatusDisplayNames.Add(PrintJobStatus.Deleted, "Deleted,");
        printJobStatusDisplayNames.Add(PrintJobStatus.BlockedDeviceQueue, "Blocked device queue,");
        printJobStatusDisplayNames.Add(PrintJobStatus.UserIntervention, "User intervention required,");
        printJobStatusDisplayNames.Add(PrintJobStatus.Restarted, "Restarted,");
        printJobStatusDisplayNames.Add(PrintJobStatus.Complete, "Complete,");
        printJobStatusDisplayNames.Add(PrintJobStatus.Retained, "Retained,");
    }
    
    /// <summary>
    /// Private constructor to prevent default instantiation.
    /// </summary>
    private DisplayablePrintJobStatus() { }

    /// <summary>
    /// Contains the mapping between PrintJobStatus fields and display strings.
    /// </summary>
    private static Dictionary<PrintJobStatus, string> printJobStatusDisplayNames;
}

步驟 4:取消列印作業

類似於顯示列印作業狀態,當您有 IPrintJob 物件時,取消列印作業相當簡單。 類別 IPrintJob 會提供方法 RequestCancel ,這個方法會起始對應列印作業的取消。 這會在範例的 CancelPrintJob_Click 方法中示範。

這個範例顯示 CancelPrintJob_Click PrintJobManagement.xaml.cs 檔案中的方法。

private void CancelPrintJob_Click(object sender, RoutedEventArgs e)
{
    try
    {
        IPrintJob job = (IPrintJob)PrintJobListBox.SelectedItem;
        job.RequestCancel();
    }
    catch (Exception exception)
    {
        rootPage.NotifyUser("Caught an exception: " + exception.Message, NotifyType.ErrorMessage);
    }
}

測試

您必須先使用裝置元數據連結到印表機,才能測試 UWP 裝置應用程式。

您需要印表機的裝置元數據套件複本,才能將裝置應用程式資訊新增至該套件。 如果您沒有裝置元數據,您可以使用裝置元數據撰寫精靈來建置它,如為 UWP 裝置應用程式建立裝置元數據主題中所述。

若要使用 裝置元數據撰寫精靈,您必須先安裝 Microsoft Visual Studio Professional、Microsoft Visual Studio Ultimate 或 適用於 Windows 8.1 的獨立 SDK,才能完成本主題中的步驟。 安裝 Microsoft Visual Studio Express for Windows 會安裝不包含精靈的 SDK 版本。

下列步驟會建置您的應用程式並安裝裝置元數據。

  1. 啟用測試簽署。

    1. 按兩下 DeviceMetadataWizard.exe,從 %ProgramFiles(x86)%\Windows Kits\8.1\bin\x86 啟動裝置元數據撰寫精靈

    2. 從 [ 工具] 功能表中,選取 [ 啟用測試簽署]。

  2. 重新啟動電腦

  3. 開啟方案 (.sln) 檔案來建置方案。 按 F7,或從範例載入後,從頂端功能表移至 [建>置方案 ]。

  4. 中斷連線並卸載印表機。 需要此步驟,Windows 會在下次偵測到裝置時讀取更新的裝置元數據。

  5. 編輯並儲存裝置元數據。 若要將裝置應用程式連結至您的裝置,您必須將裝置應用程式與裝置產生關聯。

    如果您尚未建立裝置元數據,請參閱 建立 UWP 裝置應用程式的裝置元數據。

    1. 如果裝置元數據撰寫精靈尚未開啟,請按兩下DeviceMetadataWizard.exe,從 %ProgramFiles(x86)%\Windows Kits\8.1\bin\x86 加以啟動。

    2. 按兩下 [ 編輯裝置元數據]。 這可讓您編輯現有的裝置元數據套件。

    3. 在 [ 開啟 ] 對話框中,找出與您的 UWP 裝置應用程式相關聯的裝置元數據套件。 (它有 devicemetadata-ms 擴展名。)

    4. 在 [ 指定 UWP 裝置應用程式資訊 ] 頁面上,於 [UWP 裝置應用程式] 方塊中 輸入 Microsoft Store 應用程式 資訊。 按兩下 [匯入 UWP 應用程式指令清單檔案],自動輸入套件名稱發行者名稱和 UWP 應用程式識別碼

    5. 如果您的 app 正在註冊印表機通知,請填寫 [ 通知處理程式] 方塊 。 在 [事件標識符] 中,輸入列印事件處理程序的名稱。 在 [事件資產] 中,輸入該程序代碼所在的檔名。

    6. 完成時,請按 [下一步] ,直到到達 [完成 ] 頁面為止。

    7. 在 [ 檢閱裝置元數據套件 ] 頁面上,確定所有設定都正確,然後選取 [ 將裝置元數據套件複製到本機計算機上的 元數據存放區] 複選框。 然後按一下 [儲存] 。

  6. 重新連線印表機,讓 Windows 在裝置連線時讀取更新的裝置元數據。

作業管理 (v4 印表機驅動程式)

開發 v4 列印驅動程式

雙向通訊

開始使用UWP應用程式

建立 UWP 裝置應用程式 (逐步指南)

建立 UWP 裝置應用程式的裝置元資料(逐步指南)