結合上次寫的導出Excel方法,這次上頭要求我將列頭進行一下合並
以前的效果:
改進后的效果:
在上篇文章中寫到了Excel的導出方法,這次為了避免在生產環境中使用Office組件,服務器各種權限配置的麻煩,這次就不使用Office組件來生成Excel了。
關鍵代碼如下圖:
說道這里,其實主要思路已經很明顯了。
在數據綁定結束后,重新繪制表頭替換掉原來的表頭就行了。
TableCell自定義表頭的時候是table標簽的,很方便。
另外發現了一個小技巧:
我使用Office Excel 2013 繪畫好表頭,然后直接復制,在Macromedia Dreamweaver 8的設計面板粘貼就可以貼上去了,然后轉到代碼頁面就可以快速得到table代碼。
最后貼上這幾句代碼:

1 gvw.HeaderRow.Cells.Clear(); 2 TableCell tc = new TableCell(); 3 //重新繪制表頭 4 tc.Text = "<tr> ...... </tr>"; 5 gvw.HeaderRow.Cells.Add(tc);
另外,看見博友推薦我使用NPOI.HSSF.Util組件,聽說很操作很方便。這里也推薦啦!

//- 創建 Excel HSSFWorkbook hssfworkbook = new HSSFWorkbook(); //- 創建 Sheet var sheet = hssfworkbook.CreateSheet("淘汰選項報表"); //- Sheet 里的每一個 Row NPOI.SS.UserModel.Row row; //- 創建一個“繪畫器”,這個繪畫器用於所有的圖片寫入。 //- 請注意,是所有的圖片,不可一張圖片創建一個!否則將導致沒有圖片 var patriarch = sheet.CreateDrawingPatriarch(); //- 默認單元格的樣式以及字體,是“Excel 級”的,如果對其進行設置,將導致所有的單元格都是這些字體以及樣式 //- 創建一個新的字體以及樣式,可以確保這些“單元格”獨立的字體與樣式。 //- 這里是創建一個標題的樣式 var cellFont = hssfworkbook.CreateFont(); var cellStyle = hssfworkbook.CreateCellStyle(); //- 加粗,白色前景色 cellFont.Boldweight = (short)NPOI.SS.UserModel.FontBoldWeight.BOLD; cellFont.Color = NPOI.HSSF.Util.HSSFColor.WHITE.index; //- 很費解 FillForegroundColor 這個屬性,我設置了是背景色,可從字義上來說,這個似乎叫“前景色”? //- 更令人無語的是,還有 FillBackgroundColor 屬性。真不知道做什么的。 cellStyle.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.GREY_40_PERCENT.index; //- 這個是填充的模式,可以是網格、花式等。如果需要填充單色,請使用:SOLID_FOREGROUND cellStyle.FillPattern = NPOI.SS.UserModel.FillPatternType.SOLID_FOREGROUND; //- 設置這個樣式的字體,如果沒有設置,將與所有單元格擁有共同字體! cellStyle.SetFont(cellFont); for(int i = 0 ; i <= gridView1.RowCount ; i++) {//- 遍歷行 這是 GridControl 控件的 GridView,i <= gridView1.RowCount的原因是首行我們設置為 標題行 row = sheet.CreateRow(i); foreach(GridColumn column in gridView1.Columns) { //- 確保只需要顯示的列 if(column.Visible) { //- 創建當前 row 指定列索引的 cell NPOI.SS.UserModel.Cell cell = row.CreateCell(column.VisibleIndex); //- 標題行 if(i == 0) { row.HeightInPoints = 50f; //- 設置行高 row.Height 需要 乘以 20 cell.SetCellValue(column.Caption); ; //-設置單元格內容 cell.CellStyle = cellStyle; //- 設置單元格的獨立樣式 } else { row.HeightInPoints = 100f; // 設置行高 row.Height 需要 乘以 20 object value = gridView1.GetRowCellValue(i - 1, column); //- 如果是一個圖片 if(value != null && value.GetType() == typeof(byte[])) { sheet.SetColumnWidth(column.VisibleIndex, 50 * 256);//- 設置列寬,需要 乘以 256 //- 插入圖片到 Excel,並返回一個圖片的標識 var pictureIdx = hssfworkbook.AddPicture((byte[])value, NPOI.SS.UserModel.PictureType.JPEG); //- 創建圖片的位置 var anchor = new HSSFClientAnchor( 0, 0, //- 上左 到 上右 的位置,是基於下面的行列位置 0, 0, //- 下左 到 下右 的位置,是基於下面的行列位置 column.VisibleIndex, i, column.VisibleIndex + 1, i + 1); //- 圖片輸出的位置這么計算的: //- 假設我們要將圖片放置於第 5(E) 列的第 2 行 //- 對應索引為是 4 : 1 (默認位置) //- 放置的位置就等於(默認位置)到(默認位置各自加上一行、一列) patriarch.CreatePicture(anchor, pictureIdx);//- 使用繪畫器繪畫圖片 } else { cell.SetCellValue(value.ToStringOrEmpty()); } } //- 居中 cell.CellStyle.VerticalAlignment = NPOI.SS.UserModel.VerticalAlignment.CENTER; cell.CellStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.CENTER; //- 細邊緣 cell.CellStyle.BorderBottom = NPOI.SS.UserModel.CellBorderType.THIN; cell.CellStyle.BorderLeft = NPOI.SS.UserModel.CellBorderType.THIN; cell.CellStyle.BorderRight = NPOI.SS.UserModel.CellBorderType.THIN; cell.CellStyle.BorderTop = NPOI.SS.UserModel.CellBorderType.THIN; cell.CellStyle.BottomBorderColor = NPOI.HSSF.Util.HSSFColor.BLACK.index; cell.CellStyle.LeftBorderColor = NPOI.HSSF.Util.HSSFColor.BLACK.index; cell.CellStyle.RightBorderColor = NPOI.HSSF.Util.HSSFColor.BLACK.index; cell.CellStyle.TopBorderColor = NPOI.HSSF.Util.HSSFColor.BLACK.index; } } } FileStream file = new FileStream(fileName, FileMode.Create); hssfworkbook.Write(file);//- 保存 file.Close();
新增(推薦)
通過模板(NPOI最新版)導出原生的Excel文件,並且支持excel內置函數。
NPOI:通過Nuget直接獲取最新版
數據源:List泛型集合
看上圖的模板,我在第三行定義了數據庫的字段名,然后隱藏,在遍歷過程中,通過這些名字來確定位置。即可正確導出數據。
幫助類:
1 public class ExcelHelper { 2 3 /// <summary> 4 /// 利用模板,導出到Excel 5 /// </summary> 6 /// <param name="dataList">源</param> 7 /// <param name="strFileName">生成的文件路徑、名稱</param> 8 /// <param name="strTemplateFileName">模板的文件路徑、名稱</param> 9 /// <param name="titleName">表頭名稱</param> 10 public static void ExportExcelForDtByNpoi<T>(List<T> dataList, string strFileName, string strTemplateFileName, string titleName) where T : class { 11 HttpResponse response = HttpContext.Current.Response; 12 try { 13 using (MemoryStream ms = ExportExcelForDtByNpoi<T>(dataList, strTemplateFileName, titleName)) { 14 byte[] data = ms.ToArray(); 15 response.Clear(); 16 response.Charset = "UTF-8"; 17 response.ContentType = "application/vnd-excel"; //"application/vnd.ms-excel"; 18 HttpContext.Current.Response.AddHeader("Content-Disposition", string.Format("attachment; filename=" + strFileName)); 19 HttpContext.Current.Response.BinaryWrite(data); 20 } 21 } 22 catch (Exception e) { 23 response.Write($@"<h1>導出出現錯誤!</h1> 24 錯誤詳情: 25 {e.Message}"); 26 } 27 28 } 29 30 /// <summary> 31 /// 利用模板,導出到Excel 32 /// </summary> 33 /// <param name="dataList">DataTable</param> 34 /// <param name="strTemplateFileName">模板的文件路徑、名稱</param> 35 /// <param name="titleName">表頭名稱</param> 36 /// <returns></returns> 37 private static MemoryStream ExportExcelForDtByNpoi<T>( 38 List<T> dataList, 39 string strTemplateFileName, 40 string titleName) where T : class { 41 FileStream file = new FileStream(strTemplateFileName, FileMode.Open, FileAccess.Read);//讀入excel模板 42 HSSFWorkbook workbook = new HSSFWorkbook(file); 43 string sheetName = "Sheet1"; 44 ISheet sheet = workbook.GetSheet(sheetName); 45 46 #region 表頭 47 //IRow headerRow = sheet.GetRow(0); 48 //ICell headerCell = headerRow.GetCell(0); 49 //headerCell.SetCellValue(titleName); 50 #endregion 51 52 Type type = typeof(T); 53 PropertyInfo[] pis = type.GetProperties(); 54 var piIndex = 0; 55 int rowIndex = 3; //起始行 56 IRow tag = sheet.GetRow(2); //標簽 57 foreach (T data in dataList) { 58 IRow dataRow = sheet.CreateRow(rowIndex); 59 while (piIndex < pis.Length) { 60 try { 61 var tagValue = tag.GetCell(piIndex).StringCellValue; 62 var propertyInfo = data.GetType().GetProperty(tagValue).GetValue(data, null).ToString(); 63 dataRow.CreateCell(piIndex).SetCellValue(propertyInfo); 64 } 65 catch (Exception e) { 66 dataRow.CreateCell(piIndex).SetCellValue(""); 67 } 68 piIndex++; 69 } 70 piIndex = 0; 71 rowIndex++; 72 } 73 74 // 格式化當前sheet,用於數據total計算 75 sheet.ForceFormulaRecalculation = true; 76 using (MemoryStream ms = new MemoryStream()) { 77 workbook.Write(ms); 78 ms.Flush(); 79 ms.Position = 0; 80 sheet = null; 81 workbook = null; 82 //sheet.Dispose(); 83 //workbook.Dispose();//一般只用寫這一個就OK了,他會遍歷並釋放所有資源,但當前版本有問題所以只釋放sheet 84 return ms; 85 } 86 } 87 88 }