使用EPPlus生成Excel时动态合并首列相同值并高亮总计行
嘿,作为EPPlus新手能想到这些动态需求已经超棒啦!我来一步步帮你实现首列相同值动态合并和总计行背景高亮的功能,完全适配列数随员工入职/离职变化的场景~
前提准备
首先确保你已经通过NuGet安装了EPPlus包,然后在代码里引用必要的命名空间:
using OfficeOpenXml; using OfficeOpenXml.Style; using System.Drawing; // 用于设置颜色
(注意:EPPlus 5+版本需要设置许可证,非商业用途可以添加ExcelPackage.LicenseContext = LicenseContext.NonCommercial;)
1. 动态合并首列相同值
核心思路是遍历数据行,记录上一行的首列值,和当前行对比:如果相同就延续合并范围,不同就结束上一个合并并开始新的范围。
假设你的数据结构是:第1行是表头,从第2行开始是数据行,首列是需要合并的标识(比如部门/员工姓名)。代码示例如下:
// 创建Excel包 using (var package = new ExcelPackage()) { var ws = package.Workbook.Worksheets.Add("员工数据"); // 模拟动态列数据(比如员工的月度考勤/薪资,列数随入职离职变化) var headers = new List<string> { "部门", "1月", "2月", "3月", "总计" }; // 列数可动态增减 var data = new List<List<object>> { new List<object> { "技术部", 100, 200, 300, 600 }, new List<object> { "技术部", 150, 250, 350, 750 }, new List<object> { "技术部", "", "", "", 1350 }, // 技术部总计行 new List<object> { "市场部", 80, 180, 280, 540 }, new List<object> { "市场部", "", "", "", 540 }, // 市场部总计行 new List<object> { "人事部", 50, 150, 250, 450 } }; // 写入表头 for (int col = 1; col <= headers.Count; col++) { ws.Cells[1, col].Value = headers[col - 1]; ws.Cells[1, col].Style.Font.Bold = true; } // 写入数据行 for (int row = 2; row <= data.Count + 1; row++) { var rowData = data[row - 2]; for (int col = 1; col <= rowData.Count; col++) { ws.Cells[row, col].Value = rowData[col - 1]; } } // -------------------------- // 动态合并首列相同值 // -------------------------- int startMergeRow = 2; // 从第2行开始(数据首行) string previousFirstColValue = ws.Cells[2, 1].Value?.ToString(); // 遍历所有数据行(从第3行开始对比) for (int row = 3; row <= ws.Dimension.End.Row; row++) { string currentFirstColValue = ws.Cells[row, 1].Value?.ToString(); // 如果当前行首列和上一行不同,就合并之前的范围 if (currentFirstColValue != previousFirstColValue) { // 合并从startMergeRow到row-1的首列 ws.Cells[startMergeRow, 1, row - 1, 1].Merge = true; // 设置合并单元格垂直居中(优化显示) ws.Cells[startMergeRow, 1, row - 1, 1].Style.VerticalAlignment = ExcelVerticalAlignment.Center; // 重置合并起始行和上一个值 startMergeRow = row; previousFirstColValue = currentFirstColValue; } } // 处理最后一组的合并(循环结束后别忘了最后一批) ws.Cells[startMergeRow, 1, ws.Dimension.End.Row, 1].Merge = true; ws.Cells[startMergeRow, 1, ws.Dimension.End.Row, 1].Style.VerticalAlignment = ExcelVerticalAlignment.Center; // -------------------------- // 总计行背景色高亮 // -------------------------- // 假设总计行的特征是:中间数据列为空,仅首列和总计列有值(可根据你的实际规则调整) foreach (var row in ws.Cells[2, 1, ws.Dimension.End.Row, ws.Dimension.End.Column].Rows) { bool isTotalRow = true; // 检查从第2列到倒数第2列是否为空 for (int col = 2; col <= ws.Dimension.End.Column - 1; col++) { if (!string.IsNullOrEmpty(row.Cells[col - 1].Value?.ToString())) { isTotalRow = false; break; } } if (isTotalRow) { // 设置整行背景色为浅蓝色(可自定义颜色) row.Style.Fill.PatternType = ExcelFillStyle.Solid; row.Style.Fill.BackgroundColor.SetColor(Color.LightSkyBlue); // 可选:设置字体加粗 row.Style.Font.Bold = true; } } // 保存Excel文件 File.WriteAllBytes("员工数据.xlsx", package.GetAsByteArray()); }
关键细节说明
- 动态列适配:代码里用
ws.Dimension.End.Column获取当前工作表的最后一列,不管列数怎么变化都能自动适配,不用硬编码列号。 - 合并逻辑:通过记录
startMergeRow跟踪合并起始行,每次遇到不同值就结束上一个合并,确保首列相同的行都能被正确合并。 - 总计行判断:示例里用“中间列为空”作为判断依据,你可以根据自己的实际数据规则调整(比如某列明确标记了"总计",或者行的某个字段是汇总标识)。
- 样式优化:合并后设置垂直居中,总计行加粗+背景色,让表格更美观。
如果还有不清楚的地方,随时问哦!
内容的提问来源于stack exchange,提问作者Nova
相关产品推荐
相关产品推荐

