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

使用iTextSharp导出GridView到PDF,如何每页显示表头且表头在上?

iTextSharp导出GridView到PDF时表头与数据混排问题的解决方法

问题描述

我正在使用iTextSharp库将GridView数据导出为PDF,目前遇到问题:表头(列标题)与数据混排,且数据显示在表头上方。我需要实现每页都显示表头,且表头位于数据上方。我尝试在PageEventHelper类的OnEndPage事件中添加表头,但未解决问题,相关代码如下:

导出方法代码

[WebMethod]
public byte[] ExportGridViewToPdf(string[][] gridData, string[] columnNames)
{
    try
    {
        Document document = new Document(PageSize.A4, 10f, 10f, 10f, 0f);
        var ms = new MemoryStream();
        var writer = PdfWriter.GetInstance(document, ms);
        var tahomaFontFile = Path.Combine(
 Environment.GetFolderPath(Environment.SpecialFolder.Fonts),
 "Tahoma.ttf");
        var tahomaBaseFont = BaseFont.CreateFont(tahomaFontFile,
 BaseFont.IDENTITY_H,
 BaseFont.EMBEDDED);
        var tahomaFont = new Font(tahomaBaseFont, 8, Font.NORMAL);
        PageEventHelper pageEventHelper = new PageEventHelper(columnNames, tahomaFont, gridData);
        writer.PageEvent = pageEventHelper;
        document.Open();

        var table = new PdfPTable(columnNames.Length)
        {
            RunDirection = PdfWriter.RUN_DIRECTION_RTL
        };
        table.WidthPercentage = 100;

        foreach (var row in gridData)
        {
            var cells = new PdfPCell[columnNames.Length];
            for (int i = 0; i < columnNames.Length; i++)
            {
                cells[i] = new PdfPCell(new Phrase(row[i], tahomaFont));
                cells[i].FixedHeight = 25f;
                table.AddCell(cells[i]); // Add each cell individually
            }
        }

        document.Add(table);

        document.Close();
        writer.Close();
        HttpContext.Current.Response.ContentType = "application/pdf";
        return ms.ToArray();
    }
    catch (Exception ex)
    {
        throw new Exception("Error exporting GridView to PDF: " + ex.Message);
    }
}

PageEventHelper类代码

using iText.Kernel.Pdf;
using iTextSharp.text;
using iTextSharp.text.pdf;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Web;

namespace EREG.BusinessLayer
{
    public class PageEventHelper : PdfPageEventHelper
    {
        private int pageNumber = 0;
        private int totalPages = 0;
        PdfTemplate footerTemplate;
        BaseFont bf = null;
        PdfContentByte cb;
        private readonly string[] _columnNames;
        private readonly iTextSharp.text.Font _tahomaFont;
        private readonly string[][] _gridData;
        public PageEventHelper(string[] columnNames, iTextSharp.text.Font tahomaFont, string[][] gridData)
        {
            _columnNames = columnNames;
            _tahomaFont = tahomaFont;
            _gridData = gridData;
        }
        
        public override void OnOpenDocument(iTextSharp.text.pdf.PdfWriter writer, Document document)
        {
            try
            {
                bf = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
                cb = writer.DirectContent;
                footerTemplate = cb.CreateTemplate(50, 50);
            }
            catch (DocumentException de)
            {
                //handle exception here
            }
            catch (System.IO.IOException ioe)
            {
                //handle exception here
            }
        }
        public override void OnStartPage(iTextSharp.text.pdf.PdfWriter writer, Document document)
        {
            base.OnStartPage(writer, document);
            pageNumber++;
        }
        public override void OnCloseDocument(iTextSharp.text.pdf.PdfWriter writer, Document document)
        {
            base.OnCloseDocument(writer, document);
            //totalPages = writer.PageNumber;
            footerTemplate.BeginText();
            footerTemplate.SetFontAndSize(bf, 12);
            footerTemplate.SetTextMatrix(0, 0);
            footerTemplate.ShowText((writer.PageNumber - 1).ToString());
            footerTemplate.EndText();
        }

        public override void OnEndPage(iTextSharp.text.pdf.PdfWriter writer, Document document)
        {
            base.OnEndPage(writer, document);

            // Create a new PdfContentByte instance
            PdfContentByte cb = writer.DirectContent;

            // Add page number at the bottom
            string pageNumberText = $"Page {writer.PageNumber} of ";
            float pageNumberWidth = bf.GetWidthPoint(pageNumberText, 12);
            float pageNumberX = (document.PageSize.Width - pageNumberWidth) / 2;
            float pageNumberY = document.BottomMargin;

            cb.BeginText();
            cb.SetFontAndSize(bf, 12);
            cb.SetTextMatrix(pageNumberX, pageNumberY);
            cb.ShowText(pageNumberText);
            cb.EndText();

            // Add the total pages placeholder
            cb.AddTemplate(footerTemplate, pageNumberX + pageNumberWidth, pageNumberY);

            // Create and add the header table
            PdfPTable headerTable = new PdfPTable(_columnNames.Length) { RunDirection = iTextSharp.text.pdf.PdfWriter.RUN_DIRECTION_RTL };
            
            foreach (var columnName in _columnNames)
            {
                var cell = new PdfPCell(new Phrase(columnName, _tahomaFont));
                cell.BackgroundColor = new BaseColor(System.Drawing.Color.LightGray);
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                headerTable.AddCell(cell);
            }
            
            headerTable.WriteSelectedRows(0, -1, document.LeftMargin, document.PageSize.Height - document.TopMargin - 20, cb);
        }
    }
}

解决方案

问题根源

在OnEndPage事件中绘制表头是在页面内容写完后执行的,这会导致表头覆盖在数据上方,出现混排。同时手动绘制表头没有和表格的布局逻辑联动,无法保证表头与数据的正确层级关系。

正确实现步骤

使用iTextSharp内置的表格表头重复机制,这是官方推荐的可靠方案:

  1. 修改导出方法中的表格逻辑,直接添加表头并设置重复属性
[WebMethod]
public byte[] ExportGridViewToPdf(string[][] gridData, string[] columnNames)
{
    try
    {
        // 调整顶部边距,给表头预留空间
        Document document = new Document(PageSize.A4, 10f, 10f, 30f, 10f);
        var ms = new MemoryStream();
        var writer = PdfWriter.GetInstance(document, ms);
        var tahomaFontFile = Path.Combine(
 Environment.GetFolderPath(Environment.SpecialFolder.Fonts),
 "Tahoma.ttf");
        var tahomaBaseFont = BaseFont.CreateFont(tahomaFontFile,
 BaseFont.IDENTITY_H,
 BaseFont.EMBEDDED);
        var tahomaFont = new Font(tahomaBaseFont, 8, Font.NORMAL);
        // 移除gridData参数,事件类不需要数据
        PageEventHelper pageEventHelper = new PageEventHelper(columnNames, tahomaFont);
        writer.PageEvent = pageEventHelper;
        document.Open();

        var table = new PdfPTable(columnNames.Length)
        {
            RunDirection = PdfWriter.RUN_DIRECTION_RTL,
            WidthPercentage = 100
        };

        // 添加表头行
        foreach (var columnName in columnNames)
        {
            var cell = new PdfPCell(new Phrase(columnName, tahomaFont));
            cell.BackgroundColor = new BaseColor(System.Drawing.Color.LightGray);
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            cell.FixedHeight = 25f;
            table.AddCell(cell);
        }
        // 设置第一行为表头,每页自动重复
        table.HeaderRows = 1;

        // 添加数据行
        foreach (var row in gridData)
        {
            var cells = new PdfPCell[columnNames.Length];
            for (int i = 0; i < columnNames.Length; i++)
            {
                cells[i] = new PdfPCell(new Phrase(row[i], tahomaFont));
                cells[i].FixedHeight = 25f;
                table.AddCell(cells[i]);
            }
        }

        document.Add(table);

        document.Close();
        writer.Close();
        HttpContext.Current.Response.ContentType = "application/pdf";
        return ms.ToArray();
    }
    catch (Exception ex)
    {
        throw new Exception("Error exporting GridView to PDF: " + ex.Message);
    }
}
  1. 简化PageEventHelper类,移除手动绘制表头的代码
using iTextSharp.text;
using iTextSharp.text.pdf;
using System;
using System.IO;
using System.Web;

namespace EREG.BusinessLayer
{
    public class PageEventHelper : PdfPageEventHelper
    {
        private PdfTemplate footerTemplate;
        private BaseFont bf = null;
        private readonly string[] _columnNames;
        private readonly iTextSharp.text.Font _tahomaFont;

        public PageEventHelper(string[] columnNames, iTextSharp.text.Font tahomaFont)
        {
            _columnNames = columnNames;
            _tahomaFont = tahomaFont;
        }
        
        public override void OnOpenDocument(PdfWriter writer, Document document)
        {
            try
            {
                bf = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
                var cb = writer.DirectContent;
                footerTemplate = cb.CreateTemplate(50, 50);
            }
            catch (DocumentException de)
            {
                // 处理异常
            }
            catch (IOException ioe)
            {
                // 处理异常
            }
        }

        public override void OnCloseDocument(PdfWriter writer, Document document)
        {
            base.OnCloseDocument(writer, document);
            footerTemplate.BeginText();
            footerTemplate.SetFontAndSize(bf, 12);
            footerTemplate.SetTextMatrix(0, 0);
            footerTemplate.ShowText((writer.PageNumber - 1).ToString());
            footerTemplate.EndText();
        }

        public override void OnEndPage(PdfWriter writer, Document document)
        {
            base.OnEndPage(writer, document);

            PdfContentByte cb = writer.DirectContent;

            // 添加页码
            string pageNumberText = $"Page {writer.PageNumber} of ";
            float pageNumberWidth = bf.GetWidthPoint(pageNumberText, 12);
            float pageNumberX = (document.PageSize.Width - pageNumberWidth) / 2;
            float pageNumberY = document.BottomMargin;

            cb.BeginText();
            cb.SetFontAndSize(bf, 12);
            cb.SetTextMatrix(pageNumberX, pageNumberY);
            cb.ShowText(pageNumberText);
            cb.EndText();

            cb.AddTemplate(footerTemplate, pageNumberX + pageNumberWidth, pageNumberY);
        }
    }
}

效果说明

通过设置PdfPTable.HeaderRows = 1,iTextSharp会自动将表格的第一行识别为表头,当表格内容跨页时,会在新页面顶部自动重复绘制表头,且表头会自然位于数据上方,彻底解决混排问题。同时调整文档顶部边距,避免表头与页面顶部内容重叠。

内容的提问来源于stack exchange,提问作者ahmed salah abd elaziz elbarba

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 07:50:56