如何在 Windows 应用商店设备应用中管理打印作业

在 Windows 8.1 中,适用于打印机的 Windows 应用商店设备应用可管理打印作业。此主题使用 C# 版本的打印作业管理和打印机维护示例演示如何创建打印作业视图,监视这些作业,以及在必要时取消作业。 有关 Windows 应用商店设备应用的更多一般信息,请参阅 Windows 应用商店设备应用

C# 版本的打印作业管理和打印机维护示例使用 DeviceAppForPrinters2 项目中的 DeviceMaintenance.xaml.cs 文件演示打印机维护。为了使用 Bidi,该示例使用了 PrinterExtensionLibrary 项目中的打印机扩展库。打印机扩展库提供了一种简便方法来访问 v4 打印驱动程序的打印机扩展接口。有关详细信息,请参阅打印机扩展库概述

注意  本主题显示的代码示例均基于 C# 版本的打印作业管理和打印机维护示例。此示例还以 JavaScript 和 C++ 提供。注意,由于 C++ 可以直接访问 COM,所以 C++ 版本的示例不包含代码库项目。下载这些示例以查看最新版本的代码。

管理打印作业

Windows 8.1 在 v4 打印机驱动程序中引入了新的打印机扩展接口用于管理打印作业:IPrinterQueue2IPrinterQueueViewIPrinterQueueViewEventIPrintJobIPrintJobCollection。这些接口使监视和取消打印作业成为可能。有关更多信息,请参阅打印作业管理(v4 打印机驱动程序)

提示  C# 和 JavaScript 应用无法直接使用 COM API。 如果编写 C# 或 JavaScript Windows 应用商店设备应用,可使用打印机扩展库来访问这些接口(如此主题中所示)。

先决条件

开始之前:

  1. 请确保使用 v4 打印驱动程序安装打印机。有关详细信息,请参阅开发 v4 打印驱动程序
  2. 准备好开发用电脑。有关下载工具和创建开发者帐户的信息,请参阅入门指南
  3. 将你的应用与应用商店进行关联。有关此操作的信息,请参阅创建 Windows 应用商店设备应用
  4. 为你的打印机创建设备元数据,将其与你的应用关联起来。有关此操作的信息,请参阅创建设备元数据
  5. 为应用主页构建 UI。所有 Windows 应用商店设备应用都可从“开始”菜单启动,然后它们将全屏显示。可以使用开始菜单体验通过某种与设备特定品牌和功能相符的方式重点介绍你的产品或服务。 对于它可以使用的 UI 控件类型没有特殊限制。要了解全屏体验的设计,请参阅 Windows 应用商店设计原则
  6. 如果使用 C# 或 JavaScript 编写你的应用,则将 PrinterExtensionLibrary 项目添加到你的 Windows 应用商店设备应用解决方案。可在打印作业管理和打印机维护示例中找到此项目。

    注意  由于 C++ 可以直接访问 COM,因此 C++ 应用无需使用单独的库处理基于 COM 的打印机设备上下文。

步骤 1:查找打印机

应用必须首先找到拥有打印作业的打印机,才能管理打印作业。为此,打印作业管理和打印机维护示例包含一个名为 PrinterEnumeration(位于 PrinterEnumeration.cs 文件中)的便捷类。此类通过设备元数据查找与你的应用关联的所有打印机,然后返回一个 PrinterInfo 对象列表,其中包含每个打印机的名称和设备 ID。

此示例显示 PrintJobManagement.xaml.cs 文件中的 EnumeratePrinters_Click 方法。它展示了示例如何使用 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);
    }
}


提示  有关 PrinterEnumerationPrinterInfo 类的更多信息,请参阅 PrinterEnumeration.cs 文件。

步骤 2:获取打印机队列

识别拥有你希望管理的打印作业的打印机后,使用基于 IPrinterQueueView 接口(在 PrinterExtensionLibrary 项目的 PrinterExtensionTypes.cs 文件中定义)的对象创建打印作业的视图。 在打印作业管理和打印机维护示例中,此对象名为 currentPrinterQueueView,在每次打印机选择更改时都会重新创建。

Printer_SelectionChanged 方法中,此示例首先使用一个 PrinterInfo 对象创建一个名为 context 的打印机扩展上下文对象。然后它使用 context 上的 GetPrinterQueueView 方法创建 currentPrinterQueueView 对象。最后,添加一个事件处理程序来处理 currentPrinterQueueViewOnChanged 事件。

此示例显示 PrintJobManagement.xaml.cs 文件中的 Printer_SelectionChanged 方法。它展示了如何创建一个基于 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 comComtext = Windows.Devices.Printers.Extensions.PrintExtensionContext.FromDeviceId(queue.DeviceId);
        PrinterExtensionContext context = new PrinterExtensionContext(comComtext);

        // 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 方法。此方法负责将 PrintJobListBox 与一个 IPrintJob 对象 IEnumerable 集合重新绑定。该集合通过 PrinterQueueViewEventArgs 对象传递给该方法,这个对象在 PrinterExtensionTypes.cs 文件中定义。

此示例显示 PrintJobManagement.xaml.cs 文件中的 OnPrinterQueueViewChanged 方法。


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 方法执行。

此示例显示 PrintJobManagement.xaml.cs 文件中的 PrintJob_SelectionChanged 方法。它展示了如何基于一个 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 的静态字典来帮助以一种用户友好的文本格式显示作业状态描述。

此示例显示 PrintJobManagement.xaml.cs 文件中的 DisplayablePrintJobStatus 类。此类包含 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 方法中演示。

此示例显示 PrintJobManagement.xaml.cs 文件中的 CancelPrintJob_Click 方法。


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);
    }
}


测试

测试 Windows 应用商店设备应用之前,必须使用设备元数据将其关联到你的打印机。

  • 你需要打印机的设备元数据包的副本,以便将设备应用信息添加到其中。如果没有设备元数据,那么你可以使用“设备元数据创作向导”构建设备元数据,如创建 Windows 应用商店设备应用的设备元数据中所述。

    注意  要使用“设备元数据创作向导”,必须安装 Microsoft Visual Studio Professional 2013、Microsoft Visual Studio Ultimate 2013 或独立的 SDK for Windows 8.1,然后才能完成本主题中的步骤。安装适用于 Windows 的 Microsoft Visual Studio Express 2013 会安装一个不包含该向导的 SDK 版本。

以下步骤用于构建你的应用及安装设备元数据。

  1. 启用测试签名。
    1. %ProgramFiles(x86)%\Windows Kits\8.1\bin\x86 双击 DeviceMetadataWizard.exe,启动“设备元数据创作向导”
    2. 从“工具” 菜单中,选择“启用测试签名”
  2. 重新启动计算机
  3. 通过打开解决方案 (.sln) 文件来构建解决方案。加载该示例后,按 F7 或从页首菜单前往“生成”>“生成解决方案”

  4. 断开连接并卸载打印机。此步骤是必需的,以便 Windows 可以在下次检测到该设备时读取更新的设备元数据。
  5. 编辑并保存设备元数据。要将设备应用链接到你的设备,必须将设备应用与你的设备关联起来。

    注意  如果尚未创建设备元数据,请参阅创建 Windows 应用商店设备应用的设备元数据

    1. 如果尚未打开“设备元数据创作向导”,请从 %ProgramFiles(x86)%\Windows Kits\8.1\bin\x86 中双击 DeviceMetadataWizard.exe 以启动该向导。
    2. 单击“编辑设备元数据”。这样即可编辑现有的设备元数据包。
    3. 在“打开”对话框中,找到与你的 Windows 应用商店设备应用关联的设备元数据包(其文件扩展名为 devicemetadata-ms)。
    4. 在“指定 Windows 应用商店设备应用信息”页的“Windows 应用商店设备应用”框中,输入该 Windows 应用商店应用的信息。单击“导入 Windows 应用商店应用部件清单(manifest)文件”即可自动输入“包名称”、“发布者名称”和“Windows 应用商店应用 ID”
    5. 如果你的应用注册打印机通知,请填写“通知处理程序”框。在“事件 ID”中,输入打印事件处理程序的名称。在“事件资产”中,输入代码所在的文件的名称。

    6. 完成后,单击“下一步”,直到你来到“完成”页。
    7. 在“查看设备元数据包”页上,确保所有相关设置准确无误,然后选择“将设备元数据包复制到本地计算机上的元数据存储中”复选框。然后,单击“保存”
  6. 重新连接你的打印机,以便 Windows 在连接设备时读取更新的设备元数据。

相关主题

作业管理(v4 打印机驱动程序)
开发 v4 打印驱动程序
双向通信
Windows 应用商店应用入门
创建 Windows 应用商店设备应用(分步指南)
创建 Windows 应用商店设备应用的设备元数据(分步指南)

 

 

显示:
© 2015 Microsoft