You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用System.Printing对象打印时Commit方法抛出NotSupportedException求助

解决System.Printing中Commit方法抛出NotSupportedException的问题

你遇到的问题其实是因为System.Printing命名空间更偏向Windows打印系统的底层交互,它不会像System.Drawing.Printing.PrintDocument那样自动封装"另存为PDF"的对话框逻辑。Microsoft Print to PDF作为虚拟打印机,需要你手动指定输出文件路径并配置打印参数,否则就会抛出无信息的NotSupportedException

下面是具体的解决方案,既能用System.Printing的对象实现需求,又能弹出保存对话框生成指定内容的PDF:

核心思路

  1. 找到Windows内置的"Microsoft Print to PDF"虚拟打印队列
  2. 手动弹出保存对话框让用户选择PDF输出路径
  3. 配置PrintTicket明确输出类型为PDF并指定文件路径
  4. 用熟悉的绘图逻辑生成打印内容,通过System.Printing提交作业

完整代码示例

using System;
using System.Drawing;
using System.Printing;
using System.Windows.Forms;
using System.Windows;
using System.Windows.Media;
using System.Windows.Xps;

public void GeneratePdfWithSystemPrinting()
{
    // 1. 获取Microsoft Print to PDF打印队列
    PrintQueue pdfPrintQueue = null;
    try
    {
        // 打印队列名称必须和系统中的一致,默认是"Microsoft Print to PDF"
        pdfPrintQueue = new PrintQueue(new PrintServer(), "Microsoft Print to PDF");
    }
    catch (PrintSystemException)
    {
        MessageBox.Show("未找到Microsoft Print to PDF打印机,请先在Windows可选功能中启用它!");
        return;
    }

    // 2. 弹出保存对话框选择输出路径
    using (var saveDialog = new SaveFileDialog())
    {
        saveDialog.Filter = "PDF文件 (*.pdf)|*.pdf";
        saveDialog.FileName = $"Print_{DateTime.Now:yyyyMMddHHmmss}.pdf";
        saveDialog.Title = "保存PDF文档";
        
        if (saveDialog.ShowDialog() != DialogResult.OK)
            return; // 用户取消操作

        // 3. 创建打印作业并配置关键参数
        var printJob = pdfPrintQueue.AddJob("PDF打印任务");
        var printTicket = printJob.PrintTicket;
        
        // 必须指定输出文件和类型,这是解决Commit异常的关键
        printTicket.OutputFile = saveDialog.FileName;
        printTicket.OutputFileType = OutputFileType.Pdf;
        printJob.PrintTicket = printTicket;

        // 4. 绘制打印内容(这里用WPF的DrawingVisual,也可以替换为System.Drawing的逻辑)
        var visual = new DrawingVisual();
        using (var drawingContext = visual.RenderOpen())
        {
            var printText = $"Printing @ {DateTime.Now:yyyy-MM-dd HH:mm:ss}";
            // 配置文本样式
            var formattedText = new FormattedText(
                printText,
                System.Globalization.CultureInfo.CurrentCulture,
                FlowDirection.LeftToRight,
                new Typeface("Arial"),
                12,
                Brushes.Black);
            
            drawingContext.DrawText(formattedText, new Point(20, 20)); // 页面左上角偏移20单位
        }

        // 5. 写入内容并提交作业
        try
        {
            var writer = XpsDocumentWriter.CreateXpsDocumentWriter(printJob);
            writer.Write(visual, printTicket);
            printJob.Commit(); // 现在不会抛出NotSupportedException了
            MessageBox.Show($"PDF已成功保存到:{saveDialog.FileName}");
        }
        catch (Exception ex)
        {
            MessageBox.Show($"生成PDF失败:{ex.Message}");
            printJob.Cancel();
        }
    }
}

为什么之前会抛出异常?

你之前的代码大概率没有设置PrintTicketOutputFileOutputFileType属性:

  • Microsoft Print to PDF作为虚拟打印机,本质是把打印内容转换为PDF文件,必须明确告诉它文件要存到哪里
  • System.Drawing.Printing.PrintDocument之所以能正常工作,是因为它封装了上层逻辑,会自动触发Windows的"另存为"对话框并处理路径配置,而System.Printing需要你手动完成这些步骤

额外注意事项

  • 如果系统中没有Microsoft Print to PDF,可以在设置 > 应用 > 可选功能中添加它
  • 若你更习惯用System.Drawing的绘图逻辑,可以把PrintDocument的内容转换为XPS流后再写入打印作业
  • 确保程序有足够的权限访问打印队列和写入目标文件路径

内容的提问来源于stack exchange,提问作者BanksySan

火山引擎 最新活动