Csharp/C#教程:NPOI实现两级分组合并功能(示例讲解)分享

NPOI版本:2.2.1.0

最近公司有这样的需求:

统计每个部门下面,多个费用使用情况。部门存在多级,但统计时,只需统计到2级,2级以下的,归到第2级的部门下。并且要求,第2级部门有个小计,第1级部门需要有个合计。最后,还需提供总计。

本来对NPOI研究的还不够深入的,以前都是直接通过别人提供的代码来实现对DataTable中的数据进行全部导出,但里面不带合并,及合计功能,不满足当前需求。不得已,只有好好地研究一下了。还好,最终实现了要求。

在此,也感谢其他提供相关资料的人员,让我实现了此功能。

简要说明一下使用:

1、Export2Template2方法直接使用。DataTable原始数据,必须是已经按要求排好序的数据。全部是逐行向下处理。

2、要导出的列名,取自cellKeys中。列名必须为source中存在的。

3、相同值合并的第1列,为cellKeys[0],合并的第2列,为cellKeys[1],如需要其它列的合并,可以此基础上,按自己的需求进行调整。(合并时,只会比较上下行的数据内容)

4、要导出的数据中,数值类型,自动居右。其它类型,自动居中。

5、小计,合计,总计的字体,全部加黑

6、小计,合计,总计,自动对数值类型进行汇总。其它类型数据全部置空。

7、合并的列数:mergeColumns。如果>2,自动只处理前2列。如果<1,则不做合并处理。

直接上可用的代码

///<summary> ///根据模版导出Excel--特别处理,每个分组带合计 ///</summary> ///<paramname="source">源DataTable</param> ///<paramname="cellKeys">需要导出的对应的列字段例:string[]cellKeys={"Date","Remarks"};</param> ///<paramname="strFileName">要保存的文件名称(包含后缀)例:"要保存的文件名.xls"</param> ///<paramname="templateFile">模版文件名(包含路径后缀)例:"模板文件名.xls"</param> ///<paramname="rowIndex">从第几行开始创建数据行,第一行为0</param> ///<paramname="mergeColumns">值相同时,可合并的前几列最多支持2列1=只合并第一列,2=判断前2列</param> ///<paramname="isConver">是否覆盖数据,=false,将把原数据下移。=true,将覆盖插入行后面的数据</param> ///<paramname="isTotal">是否带小计/合计项</param> ///<paramname="addAllTotal">是否添加总计项</param> ///<returns>是否导出成功</returns> publicstaticboolExport2Template2(DataTablesource,string[]cellKeys,stringstrFileName,stringtemplateFile,introwIndex,intmergeColumns,boolisConver,boolisTotal,booladdAllTotal) { boolbn=false; intcellCount=cellKeys.Length;//总列数,第一列为0 //IWorkbookworkbook=null; HSSFWorkbookworkbook=null; stringtemp0="",temp1=""; intstart0=0,start1=0;//记录1,2列值相同的开始序号 intend0=0,end1=0;//记录1,2列值相同的结束序号 try { using(FileStreamfile=newFileStream(templateFile,FileMode.Open,FileAccess.Read)) { workbook=newHSSFWorkbook(file); } #region定义四类数据的单元格样式 //内容数据格式--数值 ICellStylestyleNum=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; //内容数据格式--字符串(做居中处理) ICellStylestyleStr=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; //汇总数据格式--数值 ICellStylestyleTotalNum=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; //设置字体颜色 HSSFFontffont0=(HSSFFont)workbook.CreateFont(); //ffont0.FontHeight=14*14; //ffont0.FontName="宋体"; ffont0.IsBold=true; //ffont0.Color=HSSFColor.Red.Index; styleTotalNum.SetFont(ffont0); //汇总数据格式--字符串(做居中处理) ICellStylestyleTotalStr=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; //设置字体颜色 HSSFFontffont1=(HSSFFont)workbook.CreateFont(); //ffont1.FontHeight=14*14; //ffont1.FontName="宋体"; ffont1.IsBold=true; //ffont.Color=HSSFColor.Red.Index; styleTotalStr.SetFont(ffont1); #endregion ISheetsheet=workbook.GetSheetAt(0);//打开第一个sheet页 if(sheet!=null&&source!=null&&source.Rows.Count>0)//模板内容为空,不做处理 { IRowrow; for(inti=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(intindex=0;index<cellCount;index++) { ICellcell=row.CreateCell(index); stringstrValue=!(source.Rows[i][cellKeys[index]]isDBNull)?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": intintV=0; int.TryParse(strValue,outintV); cell.CellStyle=styleNum;//设置格式 cell.SetCellValue(intV); break; case"System.Decimal"://浮点型 case"System.Double": case"System.Single": doubledoubV=0; double.TryParse(strValue,outdoubV); 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列值变化没 stringcellText0=source.Rows[i][cellKeys[0]].ToString(); if(temp0!=cellText0)//第1列值有变化 { #region第2列要合并 if(mergeColumns>1)//第2列要合并 { if(start1!=end1)//开始行和结束行不相同,才进行合并 { CellRangeAddressregion1=newCellRangeAddress(start1,end1,1,1);//合并第二列 sheet.AddMergedRegion(region1); } #region第2列加小计 if(isTotal)//加小计 { if(!isConver)sheet.ShiftRows(rowIndex,sheet.LastRowNum,1,true,false);//不覆盖,数据向下移 IRowrowTotal1=sheet.CreateRow(rowIndex); //创建列并插入数据 #region插入小计数据 for(intindex=0;index<cellCount;index++) { objectobj1; ICellnewcell=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)); intintV=0; int.TryParse(obj1.ToString(),outintV); 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)); doubledoubV=0; double.TryParse(obj1.ToString(),outdoubV); newcell.CellStyle=styleTotalNum; newcell.SetCellValue(doubV); break; default: newcell.CellStyle=styleTotalStr; newcell.SetCellValue(""); break; } } #endregion //合并小计 CellRangeAddressregion0=newCellRangeAddress(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)//开始行和结束行不相同,才进行合并 { CellRangeAddressregion0=newCellRangeAddress(start0,end0,0,0);//合并第二列 sheet.AddMergedRegion(region0); } #region第1列加合计 if(isTotal)//加合计 { if(!isConver)sheet.ShiftRows(rowIndex,sheet.LastRowNum,1,true,false);//不覆盖,数据向下移 IRowrowTotal0=sheet.CreateRow(rowIndex); //创建列并插入数据 #region加合计列 for(intindex=0;index<cellCount;index++) { objectobj1; ICellnewcell=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)); intintV=0; int.TryParse(obj1.ToString(),outintV); 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)); doubledoubV=0; double.TryParse(obj1.ToString(),outdoubV); newcell.CellStyle=styleTotalNum; newcell.SetCellValue(doubV); break; default: newcell.CellStyle=styleTotalStr; newcell.SetCellValue(""); break; } } #endregion //合并合计 CellRangeAddressregion0=newCellRangeAddress(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列是否有变化 stringcellText1=source.Rows[i][cellKeys[1]].ToString(); if(cellText1!=temp1)//第1列没变,第2列变化 { #region第2列要合并 if(mergeColumns>1)//第2列要合并 { if(start1!=end1)//开始行和结束行不相同,才进行合并 { CellRangeAddressregion1=newCellRangeAddress(start1,end1,1,1);//合并第二列 sheet.AddMergedRegion(region1); } #region第2列加小计 if(isTotal)//加小计 { if(!isConver)sheet.ShiftRows(rowIndex,sheet.LastRowNum,1,true,false);//不覆盖,数据向下移 IRowrowTotal1=sheet.CreateRow(rowIndex); //创建列并插入数据 #region插入小计数据 for(intindex=0;index<cellCount;index++) { objectobj1; ICellnewcell=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)); intintV=0; int.TryParse(obj1.ToString(),outintV); 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)); doubledoubV=0; double.TryParse(obj1.ToString(),outdoubV); newcell.CellStyle=styleTotalNum; newcell.SetCellValue(doubV); break; default: newcell.CellStyle=styleTotalStr; newcell.SetCellValue(""); break; } } #endregion //合并小计 CellRangeAddressregion0=newCellRangeAddress(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(intindex=0;index<cellCount;index++) { ICellcell=row.CreateCell(index);<br> stringstrValue=!(source.Rows[i][cellKeys[index]]isDBNull)?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": intintV=0; int.TryParse(strValue,outintV); cell.CellStyle=styleNum; cell.SetCellValue(intV); break; case"System.Decimal"://浮点型 case"System.Double": case"System.Single": doubledoubV=0; double.TryParse(strValue,outdoubV); 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)//开始行和结束行不等,进行合并 { CellRangeAddressregion1=newCellRangeAddress(start1,end1,1,1);//合并第二列 sheet.AddMergedRegion(region1); } #region第2列加小计 if(isTotal)//加小计 { if(!isConver)sheet.ShiftRows(rowIndex,sheet.LastRowNum,1,true,false);//不覆盖,数据向下移 IRowrowTotal1=sheet.CreateRow(rowIndex); //创建列并插入数据 #region插入小计数据 for(intindex=0;index<cellCount;index++) { objectobj1; ICellnewcell=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)); intintV=0; int.TryParse(obj1.ToString(),outintV); 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)); doubledoubV=0; double.TryParse(obj1.ToString(),outdoubV); newcell.CellStyle=styleTotalNum; newcell.SetCellValue(doubV); break; default: newcell.CellStyle=styleTotalStr; newcell.SetCellValue(""); break; } #endregion } #endregion //合并小计 CellRangeAddressregion0=newCellRangeAddress(rowIndex,rowIndex,1,2);//合并小计 sheet.AddMergedRegion(region0); rowIndex++; end0++; } #endregion } #endregion #region对第1列合并 if(mergeColumns>0)//对第1列合并 { if(start0!=end0)//开始行和结束行不等,进行合并 { CellRangeAddressregion1=newCellRangeAddress(start0,end0,0,0);//合并第二列 sheet.AddMergedRegion(region1); } #region第1列加合计 if(isTotal)//加合计 { if(!isConver)sheet.ShiftRows(rowIndex,sheet.LastRowNum,1,true,false);//不覆盖,数据向下移 IRowrowTotal0=sheet.CreateRow(rowIndex); //创建列并插入数据 #region插入合计数据 for(intindex=0;index<cellCount;index++) { objectobj1; ICellnewcell=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)); intintV=0; newcell.CellStyle=styleTotalNum; int.TryParse(obj1.ToString(),outintV); 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)); doubledoubV=0; double.TryParse(obj1.ToString(),outdoubV); newcell.CellStyle=styleTotalNum; newcell.SetCellValue(doubV); break; default: newcell.CellStyle=styleTotalStr; newcell.SetCellValue(""); break; } #endregion } #endregion //合并合计 CellRangeAddressregion0=newCellRangeAddress(rowIndex,rowIndex,0,2);//合并合计 sheet.AddMergedRegion(region0); } rowIndex++; #endregion } #endregion #region进行汇总-加总计 if(addAllTotal)//加总计 { if(!isConver)sheet.ShiftRows(rowIndex,sheet.LastRowNum,1,true,false);//不覆盖,数据向下移 IRowrowTotal0=sheet.CreateRow(rowIndex); //创建列并插入数据 #region插入总计数据 for(intindex=0;index<cellCount;index++) { objectobj1; ICellnewcell=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]),""); intintV=0; int.TryParse(obj1.ToString(),outintV); 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]),""); doubledoubV=0; double.TryParse(obj1.ToString(),outdoubV); newcell.CellStyle=styleTotalNum; newcell.SetCellValue(doubV); break; default: newcell.CellStyle=styleTotalStr; newcell.SetCellValue(""); break; } #endregion } #endregion //合并总计 CellRangeAddressregion0=newCellRangeAddress(rowIndex,rowIndex,0,2);//合并总计 sheet.AddMergedRegion(region0); } #endregion } returnSave2Xls(strFileName,workbook);//保存为xls文件 } catch(Exceptionex) { //FileHelper.WriteLine(logfile,"处理数据异常:"+ex.Message); //msg=ex.Message; } returnbn; }

保存文件的代码:

publicstaticboolSave2Xls(stringfileName,IWorkbookworkbook) { boolbn=false; try { FileStreamfs=newFileStream(fileName,FileMode.OpenOrCreate); MemoryStreamms=newMemoryStream(); workbook.Write(ms); BinaryWriterw=newBinaryWriter(fs); w.Write(ms.ToArray()); fs.Close(); ms.Close(); bn=true; } catch(Exceptionex) { //FileHelper.WriteLine(logfile,"保存文件异常:"+ex.Message); } returnbn; }

上述就是C#学习教程:NPOI实现两级分组合并功能(示例讲解)分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/cdevelopment/908110.html

(0)
上一篇 2021年10月25日
下一篇 2021年10月25日

精彩推荐