本篇文章为大家展示了怎么在NPOI中实现两级分组合并功能,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。
/// <summary>
/// 根据模版导出Excel -- 特别处理,每个分组带合计
/// </summary>
/// <param name="source">源DataTable</param>
/// <param name="cellKeys">需要导出的对应的列字段 例:string[] cellKeys = { "Date","Remarks" };</param>
/// <param name="strFileName">要保存的文件名称(包含后缀) 例:"要保存的文件名.xls"</param>
/// <param name="templateFile">模版文件名(包含路径后缀) 例:"模板文件名.xls"</param>
/// <param name="rowIndex">从第几行开始创建数据行,第一行为0</param>
/// <param name="mergeColumns">值相同时,可合并的前几列 最多支持2列 1=只合并第一列,2=判断前2列</param>
/// <param name="isConver">是否覆盖数据,=false,将把原数据下移。=true,将覆盖插入行后面的数据</param>
/// <param name="isTotal">是否带小计/合计项</param>
/// <param name="addAllTotal">是否添加总计项</param>
/// <returns>是否导出成功</returns>
public static bool Export2Template2(DataTable source, string[] cellKeys, string strFileName, string templateFile, int rowIndex, int mergeColumns, bool isConver, bool isTotal, bool addAllTotal)
{
bool bn = false;
int cellCount = cellKeys.Length; //总列数,第一列为0
// IWorkbook workbook = null;
HSSFWorkbook workbook = null;
string temp0 = "", temp1 = "";
int start0 = 0, start1 = 0; // 记录1,2列值相同的开始序号
int end0 = 0, end1 = 0;// 记录1,2列值相同的结束序号
try
{
using (FileStream file = new FileStream(templateFile, FileMode.Open, FileAccess.Read))
{
workbook = new HSSFWorkbook(file);
}
#region 定义四类数据的单元格样式
// 内容数据格式 -- 数值
ICellStyle styleNum = workbook.CreateCellStyle();
styleNum.BorderBottom = BorderStyle.Thin;
styleNum.BorderLeft = BorderStyle.Thin;
styleNum.BorderRight = BorderStyle.Thin;
styleNum.BorderTop = BorderStyle.Thin;
// styleNum.VerticalAlignment = VerticalAlignment.Center;
// styleNum.Alignment = HorizontalAlignment.Center;
// 内容数据格式 -- 字符串(做居中处理)
ICellStyle styleStr = workbook.CreateCellStyle();
styleStr.BorderBottom = BorderStyle.Thin;
styleStr.BorderLeft = BorderStyle.Thin;
styleStr.BorderRight = BorderStyle.Thin;
styleStr.BorderTop = BorderStyle.Thin;
styleStr.VerticalAlignment = VerticalAlignment.Center;
styleStr.Alignment = HorizontalAlignment.Center;
// 汇总数据格式 -- 数值
ICellStyle styleTotalNum = workbook.CreateCellStyle();
styleTotalNum.BorderBottom = BorderStyle.Thin;
styleTotalNum.BorderLeft = BorderStyle.Thin;
styleTotalNum.BorderRight = BorderStyle.Thin;
styleTotalNum.BorderTop = BorderStyle.Thin;
styleTotalNum.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Grey25Percent.Index;
styleTotalNum.FillPattern = FillPattern.SolidForeground;
styleTotalNum.FillBackgroundColor = NPOI.HSSF.Util.HSSFColor.Red.Index;
// 设置字体颜色
HSSFFont ffont0 = (HSSFFont)workbook.CreateFont();
// ffont0.FontHeight = 14 * 14;
// ffont0.FontName = "宋体";
ffont0.IsBold = true;
//ffont0.Color = HSSFColor.Red.Index;
styleTotalNum.SetFont(ffont0);
// 汇总数据格式 -- 字符串(做居中处理)
ICellStyle styleTotalStr = workbook.CreateCellStyle();
styleTotalStr.BorderBottom = BorderStyle.Thin;
styleTotalStr.BorderLeft = BorderStyle.Thin;
styleTotalStr.BorderRight = BorderStyle.Thin;
styleTotalStr.BorderTop = BorderStyle.Thin;
styleTotalStr.VerticalAlignment = VerticalAlignment.Center;
styleTotalStr.Alignment = HorizontalAlignment.Center;
styleTotalStr.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Grey25Percent.Index;
styleTotalStr.FillPattern = FillPattern.SolidForeground;
// 设置字体颜色
HSSFFont ffont1 = (HSSFFont)workbook.CreateFont();
// ffont1.FontHeight = 14 * 14;
// ffont1.FontName = "宋体";
ffont1.IsBold = true;
//ffont.Color = HSSFColor.Red.Index;
styleTotalStr.SetFont(ffont1);
#endregion
ISheet sheet = workbook.GetSheetAt(0); // 打开第一个sheet页
if (sheet != null && source != null && source.Rows.Count > 0) // 模板内容为空,不做处理
{
IRow row;
for (int i = 0, len = source.Rows.Count; i < len; i++)
{
if (!isConver) sheet.ShiftRows(rowIndex, sheet.LastRowNum, 1, true, false); // 不覆盖,数据向下移
#region 第一行,写入数据后,对变量赋初值
if (i == 0) // 第一行,赋初值
{
row = sheet.CreateRow(rowIndex);
#region 创建列并插入数据
//创建列并插入数据
for (int index = 0; index < cellCount; index++)
{
ICell cell = row.CreateCell(index);
string strValue = !(source.Rows[i][cellKeys[index]] is DBNull) ? source.Rows[i][cellKeys[index]].ToString() : string.Empty;
// 其它列数据,数值进行汇总
switch (source.Columns[cellKeys[index]].DataType.ToString())
{
case "System.Int16": //整型
case "System.Int32":
case "System.Int64":
case "System.Byte":
int intV = 0;
int.TryParse(strValue, out intV);
cell.CellStyle = styleNum; // 设置格式
cell.SetCellValue(intV);
break;
case "System.Decimal": //浮点型
case "System.Double":
case "System.Single":
double doubV = 0;
double.TryParse(strValue, out doubV);
cell.CellStyle = styleNum; // 设置格式
cell.SetCellValue(doubV);
break;
default:
cell.CellStyle = styleStr; // 设置格式
cell.SetCellValue(strValue);
break;
}
}
#endregion
if (mergeColumns > 0)
{
temp0 = source.Rows[i][cellKeys[0]].ToString(); // 保存第1列值
start0 = rowIndex;
end0 = rowIndex;
}
if (mergeColumns > 1)
{
temp1 = source.Rows[i][cellKeys[1]].ToString(); // 保存第2列值
start1 = rowIndex;
end1 = rowIndex;
}
rowIndex++;
continue;
}
#endregion
// 不是第一行数据的处理
// 判断1列值变化没
string cellText0 = source.Rows[i][cellKeys[0]].ToString();
if (temp0 != cellText0) // 第1列值有变化
{
#region 第2列要合并
if (mergeColumns > 1) // 第2列要合并
{
if (start1 != end1) // 开始行和结束行不相同,才进行合并
{
CellRangeAddress region1 = new CellRangeAddress(start1, end1, 1, 1); // 合并第二列
sheet.AddMergedRegion(region1);
}
#region 第2列加小计
if (isTotal) // 加小计
{
if (!isConver) sheet.ShiftRows(rowIndex, sheet.LastRowNum, 1, true, false); // 不覆盖,数据向下移
IRow rowTotal1 = sheet.CreateRow(rowIndex);
//创建列并插入数据
#region 插入小计数据
for (int index = 0; index < cellCount; index++)
{
object obj1;
ICell newcell = rowTotal1.CreateCell(index);
if (index == 0) //第1列
{
newcell.CellStyle = styleTotalStr;
newcell.SetCellValue(temp0);
continue;
}
if (index == 1) // 第2列
{
newcell.CellStyle = styleTotalStr;
newcell.SetCellValue("小计");
continue;
}
// 其它列数据,数值进行汇总
switch (source.Columns[cellKeys[index]].DataType.ToString())
{
case "System.Int16": //整型
case "System.Int32":
case "System.Int64":
case "System.Byte":
obj1 = source.Compute(string.Format("sum({0})", cellKeys[index]), string.Format("{0} = '{1}' and {2} = '{3}' ", cellKeys[0], temp0, cellKeys[1], temp1));
int intV = 0;
int.TryParse(obj1.ToString(), out intV);
newcell.CellStyle = styleTotalNum;
newcell.SetCellValue(intV);
break;
case "System.Decimal": //浮点型
case "System.Double":
case "System.Single":
obj1 = source.Compute(string.Format("sum({0})", cellKeys[index]), string.Format("{0} = '{1}' and {2} = '{3}' ", cellKeys[0], temp0, cellKeys[1], temp1));
double doubV = 0;
double.TryParse(obj1.ToString(), out doubV);
newcell.CellStyle = styleTotalNum;
newcell.SetCellValue(doubV);
break;
default:
newcell.CellStyle = styleTotalStr;
newcell.SetCellValue("");
break;
}
}
#endregion
// 合并小计
CellRangeAddress region0 = new CellRangeAddress(rowIndex, rowIndex, 1, 2); // 合并小计
sheet.AddMergedRegion(region0);
}
#endregion
temp1 = source.Rows[i][cellKeys[1]].ToString();
end0++;
rowIndex++;
}
#endregion
#region 第1列要合并
if (mergeColumns > 0) // 第1列要合并
{
if (start0 != end0) // 开始行和结束行不相同,才进行合并
{
CellRangeAddress region0 = new CellRangeAddress(start0, end0, 0, 0); // 合并第二列
sheet.AddMergedRegion(region0);
}
#region 第1列加合计
if (isTotal) // 加合计
{
if (!isConver) sheet.ShiftRows(rowIndex, sheet.LastRowNum, 1, true, false); // 不覆盖,数据向下移
IRow rowTotal0 = sheet.CreateRow(rowIndex);
//创建列并插入数据
#region 加合计列
for (int index = 0; index < cellCount; index++)
{
object obj1;
ICell newcell = rowTotal0.CreateCell(index);
if (index == 0)
{
newcell.CellStyle = styleTotalStr;
newcell.SetCellValue("合计"); //第1列
continue;
}
if (index == 1)
{
newcell.CellStyle = styleTotalStr;
newcell.SetCellValue(""); // 第2列
continue;
}
switch (source.Columns[cellKeys[index]].DataType.ToString())
{
case "System.Int16": //整型
case "System.Int32":
case "System.Int64":
case "System.Byte":
obj1 = source.Compute(string.Format("sum({0})", cellKeys[index]), string.Format("{0} = '{1}' ", cellKeys[0], temp0));
int intV = 0;
int.TryParse(obj1.ToString(), out intV);
newcell.CellStyle = styleTotalNum;
newcell.SetCellValue(intV);
break;
case "System.Decimal": //浮点型
case "System.Double":
case "System.Single":
obj1 = source.Compute(string.Format("sum({0})", cellKeys[index]), string.Format("{0} = '{1}' ", cellKeys[0], temp0));
double doubV = 0;
double.TryParse(obj1.ToString(), out doubV);
newcell.CellStyle = styleTotalNum;
newcell.SetCellValue(doubV);
break;
default:
newcell.CellStyle = styleTotalStr;
newcell.SetCellValue("");
break;
}
}
#endregion
// 合并合计
CellRangeAddress region0 = new CellRangeAddress(rowIndex, rowIndex, 0, 2); // 合并合计
sheet.AddMergedRegion(region0);
end0++;
rowIndex++;
}
#endregion
temp0 = cellText0;
}
#endregion
// 重新赋值
start0 = rowIndex;
end0 = rowIndex;
start1 = rowIndex;
end1 = rowIndex;
}
else // 第1列值没有变化
{
end0++;
// 判断第2列是否有变化
string cellText1 = source.Rows[i][cellKeys[1]].ToString();
if (cellText1 != temp1) // 第1列没变,第2列变化
{
#region 第2列要合并
if (mergeColumns > 1) // 第2列要合并
{
if (start1 != end1) // 开始行和结束行不相同,才进行合并
{
CellRangeAddress region1 = new CellRangeAddress(start1, end1, 1, 1); // 合并第二列
sheet.AddMergedRegion(region1);
}
#region 第2列加小计
if (isTotal) // 加小计
{
if (!isConver) sheet.ShiftRows(rowIndex, sheet.LastRowNum, 1, true, false); // 不覆盖,数据向下移
IRow rowTotal1 = sheet.CreateRow(rowIndex);
//创建列并插入数据
#region 插入小计数据
for (int index = 0; index < cellCount; index++)
{
object obj1;
ICell newcell = rowTotal1.CreateCell(index);
if (index == 0) //第1列
{
newcell.CellStyle = styleTotalStr;
newcell.SetCellValue(temp0);
continue;
}
if (index == 1) // 第2列
{
newcell.CellStyle = styleTotalStr;
newcell.SetCellValue("小计");
continue;
}
// 其它列数据,数值进行汇总
switch (source.Columns[cellKeys[index]].DataType.ToString())
{
case "System.Int16": //整型
case "System.Int32":
case "System.Int64":
case "System.Byte":
obj1 = source.Compute(string.Format("sum({0})", cellKeys[index]), string.Format("{0} = '{1}' and {2} = '{3}' ", cellKeys[0], temp0, cellKeys[1], temp1));
int intV = 0;
int.TryParse(obj1.ToString(), out intV);
newcell.CellStyle = styleTotalNum;
newcell.SetCellValue(intV);
break;
case "System.Decimal": //浮点型
case "System.Double":
case "System.Single":
obj1 = source.Compute(string.Format("sum({0})", cellKeys[index]), string.Format("{0} = '{1}' and {2} = '{3}' ", cellKeys[0], temp0, cellKeys[1], temp1));
double doubV = 0;
double.TryParse(obj1.ToString(), out doubV);
newcell.CellStyle = styleTotalNum;
newcell.SetCellValue(doubV);
break;
default:
newcell.CellStyle = styleTotalStr;
newcell.SetCellValue("");
break;
}
}
#endregion
// 合并小计
CellRangeAddress region0 = new CellRangeAddress(rowIndex, rowIndex, 1, 2); // 合并小计
sheet.AddMergedRegion(region0);
end0++;
rowIndex++;
}
temp1 = cellText1; // 要合并,才进行重新赋值
start1 = rowIndex;
end1 = rowIndex;
#endregion
}
#endregion
}
else // 第1列值没变,第2列也没变
end1++;
}
// 插入当前数据
row = sheet.CreateRow(rowIndex);
#region 创建行并插入当前记录的数据
//创建行并插入当前记录的数据
for (int index = 0; index < cellCount; index++)
{
ICell cell = row.CreateCell(index);<br>
string strValue = !(source.Rows[i][cellKeys[index]] is DBNull) ? source.Rows[i][cellKeys[index]].ToString() : string.Empty; // 取值
switch (source.Columns[cellKeys[index]].DataType.ToString())
{
case "System.Int16": //整型
case "System.Int32":
case "System.Int64":
case "System.Byte":
int intV = 0;
int.TryParse(strValue, out intV);
cell.CellStyle = styleNum;
cell.SetCellValue(intV);
break;
case "System.Decimal": //浮点型
case "System.Double":
case "System.Single":
double doubV = 0;
double.TryParse(strValue, out doubV);
cell.CellStyle = styleNum;
cell.SetCellValue(doubV);
break;
default:
cell.CellStyle = styleStr;
cell.SetCellValue(strValue);
break;
}
}
#endregion
// 下移一行
rowIndex++;
}
// 最后一条记录的合计
#region 对第2列进行合并
if (mergeColumns > 1) // 对第2列合并
{
if (start1 != end1) // 开始行和结束行不等,进行合并
{
CellRangeAddress region1 = new CellRangeAddress(start1, end1, 1, 1); // 合并第二列
sheet.AddMergedRegion(region1);
}
#region 第2列加小计
if (isTotal) // 加小计
{
if (!isConver) sheet.ShiftRows(rowIndex, sheet.LastRowNum, 1, true, false); // 不覆盖,数据向下移
IRow rowTotal1 = sheet.CreateRow(rowIndex);
//创建列并插入数据
#region 插入小计数据
for (int index = 0; index < cellCount; index++)
{
object obj1;
ICell newcell = rowTotal1.CreateCell(index);
#region 列值处理
if (index == 0) //第1列
{
newcell.CellStyle = styleTotalStr;
newcell.SetCellValue(temp0);
continue;
}
if (index == 1) // 第2列
{
newcell.CellStyle = styleTotalStr;
newcell.SetCellValue("小计");
continue;
}
// 其它列数据,数值进行汇总
switch (source.Columns[cellKeys[index]].DataType.ToString())
{
case "System.Int16": //整型
case "System.Int32":
case "System.Int64":
case "System.Byte":
obj1 = source.Compute(string.Format("sum({0})", cellKeys[index]), string.Format("{0} = '{1}' and {2} = '{3}' ", cellKeys[0], temp0, cellKeys[1], temp1));
int intV = 0;
int.TryParse(obj1.ToString(), out intV);
newcell.CellStyle = styleTotalNum;
newcell.SetCellValue(intV);
break;
case "System.Decimal": //浮点型
case "System.Double":
case "System.Single":
obj1 = source.Compute(string.Format("sum({0})", cellKeys[index]), string.Format("{0} = '{1}' and {2} = '{3}' ", cellKeys[0], temp0, cellKeys[1], temp1));
double doubV = 0;
double.TryParse(obj1.ToString(), out doubV);
newcell.CellStyle = styleTotalNum;
newcell.SetCellValue(doubV);
break;
default:
newcell.CellStyle = styleTotalStr;
newcell.SetCellValue("");
break;
}
#endregion
}
#endregion
// 合并小计
CellRangeAddress region0 = new CellRangeAddress(rowIndex, rowIndex, 1, 2); // 合并小计
sheet.AddMergedRegion(region0);
rowIndex++;
end0++;
}
#endregion
}
#endregion
#region 对第1列合并
if (mergeColumns > 0) // 对第1列合并
{
if (start0 != end0) // 开始行和结束行不等,进行合并
{
CellRangeAddress region1 = new CellRangeAddress(start0, end0, 0, 0); // 合并第二列
sheet.AddMergedRegion(region1);
}
#region 第1列加合计
if (isTotal) // 加合计
{
if (!isConver) sheet.ShiftRows(rowIndex, sheet.LastRowNum, 1, true, false); // 不覆盖,数据向下移
IRow rowTotal0 = sheet.CreateRow(rowIndex);
//创建列并插入数据
#region 插入合计数据
for (int index = 0; index < cellCount; index++)
{
object obj1;
ICell newcell = rowTotal0.CreateCell(index);
#region 列值处理
if (index == 0) //第1列
{
newcell.CellStyle = styleTotalStr;
newcell.SetCellValue("合计");
continue;
}
if (index == 1) // 第2列
{
newcell.CellStyle = styleTotalStr;
newcell.SetCellValue("");
continue;
}
// 其它列数据,数值进行汇总
switch (source.Columns[cellKeys[index]].DataType.ToString())
{
case "System.Int16": //整型
case "System.Int32":
case "System.Int64":
case "System.Byte":
obj1 = source.Compute(string.Format("sum({0})", cellKeys[index]), string.Format("{0} = '{1}' ", cellKeys[0], temp0));
int intV = 0;
newcell.CellStyle = styleTotalNum;
int.TryParse(obj1.ToString(), out intV);
newcell.SetCellValue(intV);
break;
case "System.Decimal": //浮点型
case "System.Double":
case "System.Single":
obj1 = source.Compute(string.Format("sum({0})", cellKeys[index]), string.Format("{0} = '{1}' ", cellKeys[0], temp0));
double doubV = 0;
double.TryParse(obj1.ToString(), out doubV);
newcell.CellStyle = styleTotalNum;
newcell.SetCellValue(doubV);
break;
default:
newcell.CellStyle = styleTotalStr;
newcell.SetCellValue("");
break;
}
#endregion
}
#endregion
// 合并合计
CellRangeAddress region0 = new CellRangeAddress(rowIndex, rowIndex, 0, 2); // 合并合计
sheet.AddMergedRegion(region0);
}
rowIndex++;
#endregion
}
#endregion
#region 进行汇总 - 加总计
if (addAllTotal) // 加总计
{
if (!isConver) sheet.ShiftRows(rowIndex, sheet.LastRowNum, 1, true, false); // 不覆盖,数据向下移
IRow rowTotal0 = sheet.CreateRow(rowIndex);
//创建列并插入数据
#region 插入总计数据
for (int index = 0; index < cellCount; index++)
{
object obj1;
ICell newcell = rowTotal0.CreateCell(index);
#region 列值处理
if (index == 0) //第1列
{
newcell.CellStyle = styleTotalStr;
newcell.SetCellValue("总计");
continue;
}
if (index == 1) // 第2列
{
newcell.CellStyle = styleTotalStr;
newcell.SetCellValue("");
continue;
}
// 其它列数据,数值进行汇总
switch (source.Columns[cellKeys[index]].DataType.ToString())
{
case "System.Int16": //整型
case "System.Int32":
case "System.Int64":
case "System.Byte":
obj1 = source.Compute(string.Format("sum({0})", cellKeys[index]), "");
int intV = 0;
int.TryParse(obj1.ToString(), out intV);
newcell.CellStyle = styleTotalNum;
newcell.SetCellValue(intV);
break;
case "System.Decimal": //浮点型
case "System.Double":
case "System.Single":
obj1 = source.Compute(string.Format("sum({0})", cellKeys[index]), "");
double doubV = 0;
double.TryParse(obj1.ToString(), out doubV);
newcell.CellStyle = styleTotalNum;
newcell.SetCellValue(doubV);
break;
default:
newcell.CellStyle = styleTotalStr;
newcell.SetCellValue("");
break;
}
#endregion
}
#endregion
// 合并总计
CellRangeAddress region0 = new CellRangeAddress(rowIndex, rowIndex, 0, 2); // 合并总计
sheet.AddMergedRegion(region0);
}
#endregion
}
return Save2Xls(strFileName, workbook); // 保存为xls文件
}
catch (Exception ex)
{
// FileHelper.WriteLine(logfile, "处理数据异常:" + ex.Message);
// msg = ex.Message;
}
return bn;
}
保存文件的代码:
public static bool Save2Xls(string fileName, IWorkbook workbook)
{
bool bn = false;
try
{
FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate);
MemoryStream ms = new MemoryStream();
workbook.Write(ms);
BinaryWriter w = new BinaryWriter(fs);
w.Write(ms.ToArray());
fs.Close();
ms.Close();
bn = true;
}
catch(Exception ex)
{
//FileHelper.WriteLine(logfile, "保存文件异常:" + ex.Message);
}
return bn;
}
上述内容就是怎么在NPOI中实现两级分组合并功能,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注亿速云行业资讯频道。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。