You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WinUI3中如何实现无预览静默打印XAML页面(指定Microsoft Print to PDF打印机)

WinUI3中如何实现无预览静默打印XAML页面(指定Microsoft Print to PDF打印机)

嘿,刚好我之前研究过类似的需求,给你两种解决方案,看哪种更符合你的预期~

方案一:跳过打印预览,直接弹出PDF保存对话框(基于Windows.UI.Xaml.Printing框架)

这个方案是在你现有的Windows.UI.Xaml.Printing示例基础上修改的,点击按钮后会直接触发Microsoft Print to PDF的保存流程,跳过默认的打印预览窗口:

步骤1:初始化打印相关对象

在你的页面类中定义所需的变量,并在页面加载时完成初始化:

private PrintDocument _printDocument;
private PrintManager _printManager;
private FrameworkElement _printContent; // 要打印的XAML元素(比如当前Page或某个Grid)

public MainPage()
{
    this.InitializeComponent();
    _printContent = this; // 这里假设打印当前整个页面,你可以替换成目标元素
    InitializePrinting();
}

private void InitializePrinting()
{
    _printManager = PrintManager.GetForCurrentView();
    _printManager.PrintTaskRequested += PrintManager_PrintTaskRequested;

    _printDocument = new PrintDocument();
    _printDocument.Paginate += PrintDocument_Paginate;
    _printDocument.GetPreviewPage += PrintDocument_GetPreviewPage;
    _printDocument.AddPages += PrintDocument_AddPages;
}

步骤2:实现打印内容的核心事件

这几个事件是告诉系统要打印什么内容,和普通打印预览的逻辑一致:

// 设置打印页数
private void PrintDocument_Paginate(object sender, PaginateEventArgs e)
{
    _printDocument.SetPreviewPageCount(1, PreviewPageCountType.Final);
}

// 返回预览页(虽然跳过预览,但系统仍需要这个步骤生成打印内容)
private void PrintDocument_GetPreviewPage(object sender, GetPreviewPageEventArgs e)
{
    _printDocument.SetPreviewPage(e.PageNumber, _printContent);
}

// 添加要打印的页面
private void PrintDocument_AddPages(object sender, AddPagesEventArgs e)
{
    _printDocument.AddPage(_printContent);
    _printDocument.AddPagesComplete();
}

步骤3:指定打印机并触发打印

在打印按钮的点击事件中触发打印流程,同时在PrintTaskRequested事件中指定目标打印机:

// 打印按钮点击事件
private async void PrintToPdfButton_Click(object sender, RoutedEventArgs e)
{
    try
    {
        // 触发打印流程
        await PrintManager.ShowPrintUIAsync();
    }
    catch (Exception ex)
    {
        var errorDialog = new ContentDialog
        {
            Title = "打印失败",
            Content = $"出错啦:{ex.Message}",
            PrimaryButtonText = "确定"
        };
        await errorDialog.ShowAsync();
    }
}

// 打印任务请求事件,指定打印机
private void PrintManager_PrintTaskRequested(PrintManager sender, PrintTaskRequestedEventArgs args)
{
    var deferral = args.Request.GetDeferral();

    // 创建打印任务
    var printTask = args.Request.CreatePrintTask("XAML页面转PDF", sourceArgs =>
    {
        // 设置打印源
        sourceArgs.SetSource(_printDocument.DocumentSource);
        // 指定目标打印机为Microsoft Print to PDF
        printTask.PrinterDisplayName = "Microsoft Print to PDF";
        // 隐藏不必要的打印选项,让界面更简洁
        printTask.Options.DisplayedOptions.Clear();
        printTask.Options.DisplayedOptions.Add(PrintOptionName.Orientation);
        printTask.Options.DisplayedOptions.Add(PrintOptionName.MediaSize);
    });

    // 监听打印完成状态
    printTask.Completed += (s, e) =>
    {
        if (e.Completion == PrintTaskCompletion.Failed)
        {
            _ = DispatcherQueue.TryEnqueue(async () =>
            {
                var failDialog = new ContentDialog
                {
                    Title = "打印失败",
                    Content = "无法完成PDF生成",
                    PrimaryButtonText = "确定"
                };
                await failDialog.ShowAsync();
            });
        }
    };

    deferral.Complete();
}

这个方案的效果是:点击按钮后直接弹出Microsoft Print to PDF的保存文件对话框,用户选择路径后即可生成PDF,完全跳过了打印预览环节。


方案二:完全静默打印,自动生成PDF(无需用户交互)

如果你需要完全不需要用户操作,自动将PDF保存到指定路径,可以用这个方案,不过需要用到System.Printing相关的API:

步骤1:添加必要的命名空间

using System.Printing;
using System.IO;
using Windows.UI.Xaml.Media.Imaging;

步骤2:实现静默打印方法

private async void SilentPrintButton_Click(object sender, RoutedEventArgs e)
{
    try
    {
        // 1. 先把XAML页面转成临时XPS文件(打印队列需要XPS格式的源)
        var tempXpsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "TempPrint.xps");
        await SaveXamlElementToXps(_printContent, tempXpsPath);

        // 2. 获取Microsoft Print to PDF的打印队列
        var localPrintServer = new LocalPrintServer();
        var pdfPrintQueue = localPrintServer.GetPrintQueue("Microsoft Print to PDF");

        // 3. 提交打印作业
        var printJob = pdfPrintQueue.AddJob("静默生成PDF", tempXpsPath, false);

        // 4. 等待打印完成
        while (!printJob.IsCompleted && !printJob.IsFailed && !printJob.IsCanceled)
        {
            await Task.Delay(100);
        }

        // 5. 清理临时文件
        if (File.Exists(tempXpsPath))
        {
            File.Delete(tempXpsPath);
        }

        // 提示成功
        var successDialog = new ContentDialog
        {
            Title = "生成成功",
            Content = "PDF已自动保存到系统默认路径(通常是「文档」文件夹)",
            PrimaryButtonText = "确定"
        };
        await successDialog.ShowAsync();
    }
    catch (Exception ex)
    {
        var errorDialog = new ContentDialog
        {
            Title = "静默打印失败",
            Content = $"错误信息:{ex.Message}",
            PrimaryButtonText = "确定"
        };
        await errorDialog.ShowAsync();
    }
}

// 将XAML元素转换为XPS文件的辅助方法
private async Task SaveXamlElementToXps(FrameworkElement element, string outputPath)
{
    var renderBitmap = new RenderTargetBitmap();
    await renderBitmap.RenderAsync(element);

    using (var xpsDoc = new XpsDocument(outputPath, FileAccess.ReadWrite))
    {
        var xpsWriter = XpsDocument.CreateXpsDocumentWriter(xpsDoc);
        xpsWriter.Write(renderBitmap);
    }
}

注意事项

  • 这个方案生成的PDF会保存在Microsoft Print to PDF的默认输出路径(一般是C:\Users\你的用户名\Documents),如果要自定义保存路径,需要修改系统注册表或者使用第三方PDF打印机(不推荐修改注册表,可能影响系统稳定性)。
  • 需要确保你的应用有足够的文件访问权限,比如在Package.appxmanifest中添加「文档库访问」权限。

备注:内容来源于stack exchange,提问作者Biryukov Georgy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.17 11:14:31