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

Blazor Server中DevExpress控件表单自定义页眉页脚PDF打印方案咨询

可行方案汇总

方案1:利用DevExpress内置导出API(推荐,适配性最好)

既然你用的是DevExpress控件,官方自带的PDF导出与打印预览能力完全适配自身控件渲染,能精准控制内容范围:

  • 单个控件导出:DxChart、DxDashboard这类可视化控件直接调用ExportToPdfAsync方法,可指定页眉页脚。以饼图为例:
    var stream = new MemoryStream();
    await PieChart.ExportToPdfAsync(stream, new PdfExportOptions {
        Header = new PdfExportHeaderFooter { Text = "仪表详情报表" },
        Footer = new PdfExportHeaderFooter { Text = $"打印日期:{DateTime.Now:yyyy-MM-dd}" }
    });
    // 后续可将stream转为文件,供前端预览或下载
    
  • 整表单导出:用DevExpress的PrintingSystem组件手动构建打印文档,自由添加表单文本、饼图等元素,完全自定义布局与页眉页脚,还能通过DxPrintPreview控件渲染预览:
    var printingSystem = new PrintingSystem();
    var document = printingSystem.CreateDocument();
    
    // 添加表单文本内容
    var textBrick = document.BeginCreateBrick<TextBrick>();
    textBrick.Text = $"仪表编号:{Instrument.Id}";
    textBrick.Rect = new RectangleF(0, 0, 500, 20);
    document.EndCreateBrick(textBrick);
    
    // 将饼图转为图片添加到文档
    var chartImage = await PieChart.ExportToImageAsync();
    var imageBrick = document.BeginCreateBrick<ImageBrick>();
    imageBrick.Image = chartImage;
    imageBrick.Rect = new RectangleF(0, 30, 500, 300);
    document.EndCreateBrick(imageBrick);
    
    // 设置全局页眉页脚
    printingSystem.PageSettings.Header.Content.Add("自定义页眉");
    printingSystem.PageSettings.Footer.Content.Add("第 [Page] 页,共 [Pages] 页");
    
    // 绑定到预览组件显示
    PrintPreviewComponent.PrintingSystem = printingSystem;
    

方案2:前端HTML转PDF(无后端依赖)

用jsPDF+html2canvas组合精准捕获目标表单区域,临时隐藏侧边栏等无关元素,同时自定义页眉页脚:

  1. 下载jsPDF和html2canvas的脚本文件到项目wwwroot/js目录,在Blazor组件中引入:
    <script src="~/js/jspdf.umd.min.js"></script>
    <script src="~/js/html2canvas.min.js"></script>
    
  2. 编写JS交互函数(通过IJSRuntime调用):
    async function exportFormToPdf(formId) {
        // 临时隐藏侧边栏等不需要的元素
        const sidebar = document.querySelector('.sidebar');
        const originalDisplay = sidebar.style.display;
        sidebar.style.display = 'none';
        
        const formElement = document.getElementById(formId);
        const canvas = await html2canvas(formElement, {
            scale: 2, // 提升导出清晰度
            useCORS: true
        });
        
        // 恢复侧边栏显示
        sidebar.style.display = originalDisplay;
        
        const pdf = new jspdf.jsPDF('p', 'mm', 'a4');
        const imgWidth = 210;
        const pageHeight = 297;
        const imgHeight = canvas.height * imgWidth / canvas.width;
        let heightLeft = imgHeight;
        let position = 0;
        
        // 添加表单内容到PDF
        pdf.addImage(canvas.toDataURL('image/png'), 'PNG', 0, position, imgWidth, imgHeight);
        heightLeft -= pageHeight;
        
        // 处理分页(内容过长时自动分页)
        while (heightLeft >= 0) {
            position = heightLeft - imgHeight;
            pdf.addPage();
            pdf.addImage(canvas.toDataURL('image/png'), 'PNG', 0, position, imgWidth, imgHeight);
            heightLeft -= pageHeight;
        }
        
        // 添加自定义页眉页脚
        const pageCount = pdf.internal.getNumberOfPages();
        for (let i = 1; i <= pageCount; i++) {
            pdf.setPage(i);
            // 页眉居中显示
            pdf.text('仪表详情报表', 105, 10, { align: 'center' });
            // 页脚居中显示页码
            pdf.text(`第 ${i} 页 / 共 ${pageCount} 页`, 105, 290, { align: 'center' });
        }
        
        // 触发打印预览或直接下载
        pdf.autoPrint(); // 打开浏览器打印预览窗口
        // 或使用 pdf.save('仪表报表.pdf'); 直接下载
    }
    
  3. 在Blazor组件中调用该JS函数:
    [Inject] private IJSRuntime JsRuntime { get; set; }
    
    private async Task ExportFormPdf() {
        // 传入目标表单的ID
        await JsRuntime.InvokeVoidAsync("exportFormToPdf", "target-instrument-form");
    }
    

方案3:后端生成PDF(完全可控布局)

如果需要极致的布局控制,可在Blazor Server后端生成PDF,推荐使用DinkToPdf(基于wkhtmltopdf):

  1. 安装NuGet包:DinkToPdf
  2. 后端编写PDF生成逻辑,接收表单数据与饼图Base64图片,构建HTML模板转PDF:
    public byte[] GenerateInstrumentPdf(InstrumentDetails details, string chartImageBase64) {
        var converter = new SynchronizedConverter(new PdfTools());
        var pdfDoc = new HtmlToPdfDocument() {
            GlobalSettings = {
                PaperSize = PaperKind.A4,
                Margins = new MarginSettings { Top = 20, Bottom = 20 },
                Out = null // 返回字节数组而非保存到文件
            },
            Objects = {
                new ObjectSettings {
                    HtmlContent = $@"
                        <html>
                            <head>
                                <style>
                                    .form-wrapper {{ width: 90%; margin: 0 auto; }}
                                    .chart-img {{ width: 100%; max-height: 350px; margin: 20px 0; }}
                                    .footer {{ position: fixed; bottom: 10px; width: 100%; text-align: center; font-size: 12px; }}
                                </style>
                            </head>
                            <body>
                                <!-- 自定义页眉 -->
                                <h2 style='text-align: center; margin-bottom: 30px;'>仪表详情报表</h2>
                                <!-- 表单内容 -->
                                <div class='form-wrapper'>
                                    <p><strong>仪表编号:</strong>{details.Id}</p>
                                    <p><strong>仪表名称:</strong>{details.Name}</p>
                                    <p><strong>状态:</strong>{details.Status}</p>
                                    <!-- 饼图 -->
                                    <img class='chart-img' src='data:image/png;base64,{chartImageBase64}' />
                                </div>
                                <!-- 自定义页脚 -->
                                <div class='footer'>
                                    打印日期:{DateTime.Now:yyyy-MM-dd HH:mm} | 第 [page] 页 / 共 [toPage] 页
                                </div>
                            </body>
                        </html>"
                }
            }
        };
        return converter.Convert(pdfDoc);
    }
    
  3. 前端调用后端接口,获取PDF字节流后实现预览:
    [Inject] private IJSRuntime JsRuntime { get; set; }
    [Inject] private InstrumentService Service { get; set; }
    
    private async Task PreviewPdf() {
        // 将饼图转为Base64图片
        var chartImage = await PieChart.ExportToImageAsync();
        var chartBase64 = ConvertImageToBase64(chartImage);
        
        // 调用后端生成PDF
        var pdfBytes = await Service.GenerateInstrumentPdf(CurrentInstrumentDetails, chartBase64);
        
        // 前端预览PDF
        await JsRuntime.InvokeVoidAsync("previewPdf", Convert.ToBase64String(pdfBytes));
    }
    
    // 辅助方法:Image转Base64
    private string ConvertImageToBase64(Image image) {
        using var ms = new MemoryStream();
        image.Save(ms, ImageFormat.Png);
        return Convert.ToBase64String(ms.ToArray());
    }
    
    对应的JS预览函数(放在wwwroot/js中):
    function previewPdf(base64Pdf) {
        const byteCharacters = atob(base64Pdf);
        const byteNumbers = new Uint8Array(byteCharacters.length);
        for (let i = 0; i < byteCharacters.length; i++) {
            byteNumbers[i] = byteCharacters.charCodeAt(i);
        }
        const blob = new Blob([byteNumbers], { type: 'application/pdf' });
        const url = URL.createObjectURL(blob);
        window.open(url, '_blank'); // 打开新窗口预览PDF
        URL.revokeObjectURL(url); // 释放URL资源
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 21:00:09