使用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内置的表格表头重复机制,这是官方推荐的可靠方案:
- 修改导出方法中的表格逻辑,直接添加表头并设置重复属性
[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); } }
- 简化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
相关产品推荐
相关产品推荐

