如何导出保留原格式的DataTable至Excel、PDF?含样式、背景色
刚好之前帮同事解决过一模一样的需求!要导出DataTable还完整保留原格式(行背景色、列背景色、重复行的黄色高亮),核心是得先把DataTable的样式元数据存下来——毕竟默认的导出工具只会导数据,不会自动识别样式。下面分Excel和PDF两种场景给你具体实现方案:
导出到Excel(保留所有格式)
我常用EPPlus这个库(支持.NET Framework和.NET Core),它能完美还原单元格/行/列的样式。步骤分两步:
1. 先准备样式元数据
DataTable本身不直接存储样式信息,所以你需要提前把这些信息存起来:
- 用字典记录哪些行对应什么背景色
- 用HashSet标记重复行的索引(你需要先写逻辑判断哪些行是重复的,比如根据特定列的组合值)
- 同理记录列的背景色(如果有的话)
示例代码(假设已经完成重复行判断):
// 行颜色映射:键=行索引,值=背景色 Dictionary<int, Color> rowBackgroundColorMap = new Dictionary<int, Color>(); // 重复行索引集合 HashSet<int> duplicateRowIndexes = new HashSet<int>(); // 列颜色映射:键=列索引,值=背景色 Dictionary<int, Color> columnBackgroundColorMap = new Dictionary<int, Color>(); // 这里假设你已经通过业务逻辑填充了上面的映射集合
2. 用EPPlus导出并应用样式
using OfficeOpenXml; using System.Drawing; using System.IO; // 注意:EPPlus 5+需要设置LicenseContext ExcelPackage.LicenseContext = LicenseContext.NonCommercial; // 你的DataTable DataTable dt = GetYourDataTable(); using (var excelPackage = new ExcelPackage()) { // 创建工作表 var worksheet = excelPackage.Workbook.Worksheets.Add("导出数据"); // 1. 写入表头并应用列样式 for (int colIndex = 0; colIndex < dt.Columns.Count; colIndex++) { var cell = worksheet.Cells[1, colIndex + 1]; cell.Value = dt.Columns[colIndex].ColumnName; // 应用列背景色 if (columnBackgroundColorMap.ContainsKey(colIndex)) { cell.Style.Fill.PatternType = ExcelFillStyle.Solid; cell.Style.Fill.BackgroundColor.SetColor(columnBackgroundColorMap[colIndex]); } } // 2. 写入数据行并应用行样式/重复行高亮 for (int rowIndex = 0; rowIndex < dt.Rows.Count; rowIndex++) { // 写入当前行的所有单元格数据 for (int colIndex = 0; colIndex < dt.Columns.Count; colIndex++) { worksheet.Cells[rowIndex + 2, colIndex + 1].Value = dt.Rows[rowIndex][colIndex]; } // 获取当前行的所有单元格区域 var rowRange = worksheet.Cells[rowIndex + 2, 1, rowIndex + 2, dt.Columns.Count]; // 优先应用重复行的黄色高亮(如果是重复行) if (duplicateRowIndexes.Contains(rowIndex)) { rowRange.Style.Fill.PatternType = ExcelFillStyle.Solid; rowRange.Style.Fill.BackgroundColor.SetColor(Color.Yellow); } // 否则应用行背景色 else if (rowBackgroundColorMap.ContainsKey(rowIndex)) { rowRange.Style.Fill.PatternType = ExcelFillStyle.Solid; rowRange.Style.Fill.BackgroundColor.SetColor(rowBackgroundColorMap[rowIndex]); } } // 保存到文件(ASP.NET环境可以直接输出到Response) File.WriteAllBytes("导出数据.xlsx", excelPackage.GetAsByteArray()); }
导出到PDF(保留所有格式)
PDF导出我用iText7(现在的新版本,比旧版iTextSharp更稳定),核心思路和Excel一样:先准备样式元数据,再逐行逐单元格应用样式。
1. 同样先准备样式元数据
和Excel部分的rowBackgroundColorMap、duplicateRowIndexes、columnBackgroundColorMap完全一致,不用重复写。
2. 用iText7导出并应用样式
using iText.Kernel.Colors; using iText.Kernel.Pdf; using iText.Layout; using iText.Layout.Element; using System.IO; // 你的DataTable DataTable dt = GetYourDataTable(); using (var fs = new FileStream("导出数据.pdf", FileMode.Create)) { // 创建PDF文档 var pdfDocument = new PdfDocument(new PdfWriter(fs)); var document = new Document(pdfDocument); // 创建PDF表格,列数和DataTable一致 var pdfTable = new Table(dt.Columns.Count); pdfTable.SetWidthPercent(100); // 1. 添加表头并应用列样式 foreach (DataColumn col in dt.Columns) { var cell = new Cell().Add(new Paragraph(col.ColumnName)); // 应用列背景色 if (columnBackgroundColorMap.ContainsKey(col.Ordinal)) { var color = columnBackgroundColorMap[col.Ordinal]; cell.SetBackgroundColor(new DeviceRgb(color.R, color.G, color.B)); } pdfTable.AddCell(cell); } // 2. 添加数据行并应用行样式/重复行高亮 for (int rowIndex = 0; rowIndex < dt.Rows.Count; rowIndex++) { // 先添加当前行的所有单元格数据 foreach (var cellValue in dt.Rows[rowIndex].ItemArray) { pdfTable.AddCell(new Cell().Add(new Paragraph(cellValue?.ToString() ?? string.Empty))); } // 获取当前行的所有单元格,统一设置样式 var rowCells = pdfTable.GetRow(rowIndex + 1).GetCells(); // 表头是第0行,数据行从第1行开始 Color targetColor = Color.WHITE; // 优先设置重复行的黄色高亮 if (duplicateRowIndexes.Contains(rowIndex)) { targetColor = Color.YELLOW; } // 否则设置行背景色 else if (rowBackgroundColorMap.ContainsKey(rowIndex)) { var dtColor = rowBackgroundColorMap[rowIndex]; targetColor = new DeviceRgb(dtColor.R, dtColor.G, dtColor.B); } // 给当前行所有单元格应用背景色 foreach (var cell in rowCells) { cell.SetBackgroundColor(targetColor); } } // 将表格加入文档并关闭 document.Add(pdfTable); document.Close(); }
关键注意事项
- 样式元数据的来源:如果你的DataTable是从WinForms/WPF的DataGridView绑定来的,那可以直接从控件的
RowDefaultCellStyle、Rows[i].DefaultCellStyle里读取颜色,不用手动维护映射集合。 - 重复行判断逻辑:你需要自己实现重复行的识别,比如遍历DataTable,用字典记录每个行的唯一标识(比如多列拼接的字符串),出现次数大于1的就是重复行,把对应的索引加入
duplicateRowIndexes。 - 库的版本和授权:EPPlus 5+需要设置非商业授权(如果是商业用途要购买授权);iText7也有商业授权要求,个人/非商业使用没问题。
内容的提问来源于stack exchange,提问作者Ganesh Malode
相关产品推荐
相关产品推荐

