NPOI导出树形结构的EXCEL通用方法

我们先定义几个单元格颜色,以便导出的EXCEL看起来比较赏心悦目。

#region    ISheet单元格样式
        ///


        /// 返回单元格颜色样式
        ///

        /// 传入的颜色HSSFColor.Blue.Index
        /// ISheet
        ///
        public static ICellStyle cellColor(short color, IWorkbook workbook)
        {
            ICellStyle dtlStyle = workbook.CreateCellStyle();
            IFont dtlFont = workbook.CreateFont();
            dtlFont.Color = color;
            dtlStyle.SetFont(dtlFont);
            return dtlStyle;
        }
        ///
        /// 返回单元格数值型样式
        ///

        /// ISheet
        /// 数值样式0.0000
        ///
        public static ICellStyle cellNumericalFomat(IWorkbook workbook,string strFormat)
        {
            IDataFormat format = workbook.CreateDataFormat();
            ICellStyle cellPriceStyle = workbook.CreateCellStyle();
            cellPriceStyle.DataFormat = format.GetFormat(strFormat);
            return cellPriceStyle;
        }
        #endregion


然后就是导出的方法,传入的参数为dtMain数据集,fileNameEXCEL名称,headerText表格标题

 public void ExportToExcel(DataTable dtMain, string fileName, string headerText)

        {
            using (MemoryStream ms = getDataToStr(dtMain, NPOIHelper.GetWorkbookType(fileName), headerText))
            {
                NPOIHelper.SaveToFile(ms, fileName);
            }

        }

//循环数据,得到数据流

 public MemoryStream getDataToStr(DataTable dtMain, CYSoft.RunInfo.Common.NPOIHelper.WorkbookType type, string headerText)
        {
            MemoryStream ms = new MemoryStream();
            IWorkbook workbook = NPOIHelper.CreateWorkbook(type); ;
            {
                ISheet sheet = workbook.CreateSheet(headerText);
                {
                    int rowIndex = 0;
                    List heads = GetExcelHead();
                    #region 表头及样式
                    if (!string.IsNullOrEmpty(headerText))
                    {
                        IRow headerRow = sheet.CreateRow(rowIndex++);
                        headerRow.HeightInPoints = 25;
                        headerRow.CreateCell(0).SetCellValue(headerText);


                        ICellStyle headStyle = workbook.CreateCellStyle();
                        headStyle.Alignment = HorizontalAlignment.Center;


                        IFont font = workbook.CreateFont();
                        font.FontHeightInPoints = 20;
                        font.Boldweight = 700;
                        headStyle.SetFont(font);
                        headerRow.GetCell(0).CellStyle = headStyle;
                        sheet.AddMergedRegion(new CellRangeAddress(0, 0, 0, heads.Count - 1));
                    }
                    #endregion


                    #region 列头及样式
                    {
                        IRow headerRow = sheet.CreateRow(rowIndex++);
                        headerRow.HeightInPoints = 15;
                        ICellStyle headStyle = Function.cellColor(HSSFColor.Black.Index, workbook);
                        headStyle.Alignment = HorizontalAlignment.Center;
                        headStyle.FillForegroundColor = HSSFColor.BlueGrey.Index;
                        IFont font = workbook.CreateFont();
                        font.FontHeightInPoints = 10;
                        font.Boldweight = 700;
                        headStyle.SetFont(font);
                        for (int i = 0; i < heads.Count; i++)
                        {
                            ICell cell = headerRow.CreateCell(i);
                            cell.SetCellValue(heads[i]);
                            cell.CellStyle = headStyle;
                            sheet.SetColumnWidth(i, 50 * 90);
                        }
                    }
                    #endregion


                    //获取第一层级,并循环构建单元格。注:我这里的数据集第一层级是PID父级ID为空,并且Level层级为1的,这里你需要改一下符合你自己的数据集。
                    List listDr = dtMain.AsEnumerable().Where(
                        dr =>
                        string.IsNullOrEmpty(dr["PID"].SyToString())
                        && dr["Level"].SyToString() == "1"
                    ).ToList();
                    foreach (DataRow dr in listDr)
                    {
                        IRow dataRow = sheet.CreateRow(rowIndex);
                        Dictionary colMap = GetDutyColMap();
                        //根据主表该行的列名,判断该列的样式,并赋值
                        getCellByCol(dr, dataRow, colMap, workbook);
                        rowIndex++;
                        //获取该级的下级,并循环构建单元格
                        getchildDrToCell(dr, dtMain, ref rowIndex, colMap, workbook, sheet);
                    }
                }
                sheet.CreateFreezePane(dtMain.Columns.Count, 2);//冻结窗格 ,把标题和列头冻结 
                sheet.SetColumnWidth(0, 50 * 100);
                sheet.SetColumnWidth(1, 70 * 160);
                workbook.Write(ms);
            }
            return ms;
        }


///


        /// 获取下级的数据,并构建行
        ///

        /// 当前行
        /// 数据集
        /// 行号
        /// 数据列名
        /// IWorkbook
        /// ISheet
        private void getchildDrToCell(DataRow dr, DataTable dt, ref int rowIndex, Dictionary colMap, IWorkbook workbook
            , ISheet sheet)
        {
            //获取该级的下级,并循环构建单元格
            List dtlListDr = dt.AsEnumerable().Where(dtl => dtl["PID"].SyToString() == dr["ContractListDtlID"].SyToString()).ToList();
            if (dtlListDr.Count() > 0)
            {
                int startRow = rowIndex;
                foreach (DataRow drDtl in dtlListDr)
                {
                    IRow dataDtlRow = sheet.CreateRow(rowIndex);
                    //构建当前行
                    getCellByCol(drDtl, dataDtlRow, colMap, workbook);
                    rowIndex++;
                    //递归寻找下级
                    getchildDrToCell(drDtl, dt, ref rowIndex, colMap, workbook, sheet);
                }
                sheet.GroupRow(startRow, rowIndex);
                sheet.SetRowGroupCollapsed(startRow, false);
            }
        }


这个方法,实际是处理金额单价等小数位数。这里就用到了我们最开始新建的那个单元格样式几个方法。这里需要根据实际情况来写,比如单价金额需要保留几位小数四舍五入等需要特殊处理的。

//根据列,构建表格行
        private void getCellByCol(DataRow dr, IRow dataRow, Dictionary colMap, IWorkbook workbook)
        {
            //根据主表该行的列名,判断该列的样式,并赋值
            foreach (KeyValuePair kv in colMap)
            {
                ICell cell = dataRow.CreateCell(kv.Key);
                //单价是3位小数,金额0位,数量4位
                if (kv.Value == "ListQty")
                { cell.CellStyle = Function.cellNumericalFomat(workbook, "0.0000"); }
                else if (kv.Value == "Price")
                { cell.CellStyle = Function.cellNumericalFomat(workbook, "0.000"); }
                else if (kv.Value == "Money" )
                { cell.CellStyle = Function.cellNumericalFomat(workbook, "0"); }
                if (kv.Value == "Qty" || kv.Value == "Price"  || kv.Value == "Money")
                {
                    cell.SetCellValue(Convert.ToDouble(dr[kv.Value].SyToDecimal()));
                }
                else cell.SetCellValue(dr[kv.Value].SyToString());
            }
        }


这个方法是告诉程序我们需要导出的字段中文名字,

private List GetExcelHead()
        {
            List heads = new List();
            heads.AddRange(new string[] { "列名1", "列名2", "列名3", "列名4", "列名5", "列名6", "列名7" });
            return heads;
        }

这个是告诉程序我们对应的数据集里面的列名。注:这个方法必须和上面GetExcelHead列名字段严格一一对应,不允许多列少列错位。

private Dictionary GetDutyColMap()
        {
            Dictionary colMap = new Dictionary();
            colMap.Add(0, "ColumnName1");
            colMap.Add(1, "ColumnName2");
            colMap.Add(2, "ColumnName3");
            colMap.Add(3, "ColumnName4");
            colMap.Add(4, "ColumnName5");
            colMap.Add(5, "ColumnName6");
            colMap.Add(6, "ColumnName7");
            return colMap;
        }

你可能感兴趣的:(C#.net)