使用ClosedXML将Gridview导出到Excel而不发出警告:您尝试打开的文件格式不同

我正在使用ASP.NET 4.5 Webform,我有一个Gridview(具有自定义TemplateField并从sqlDataSource获取数据)

我有这个事件将gridview内容导出到excel表,并且它完成了它的工作,除了创建的文件在用户打开它时发出警告(我理解,因为创建的文件不是实际的excel文件) :

“您尝试打开的文件格式与文件扩展名指定的格式不同”

protected void btnExport_Excel_Click(object sender, EventArgs e) { try { Response.Clear(); Response.Buffer = true; Response.AddHeader("content-disposition", "attachment;filename=GV.xls"); Response.Charset = ""; Response.ContentType = "application/ms-excel"; //Response.ContentType = "application/text"; Response.ContentEncoding = System.Text.Encoding.Unicode; Response.BinaryWrite(System.Text.Encoding.Unicode.GetPreamble()); using (StringWriter sw = new StringWriter()) { HtmlTextWriter hw = new HtmlTextWriter(sw); //To Export all pages GridView4.AllowPaging = false; GridView4.AllowSorting = false; GridView4.ShowFooter = false; GridView4.DataBind(); //this.BindGrid(); GridView4.HeaderRow.BackColor = Color.White; foreach (TableCell cell in GridView4.HeaderRow.Cells) { cell.BackColor = GridView4.HeaderStyle.BackColor; } foreach (GridViewRow row in GridView4.Rows) { row.BackColor = Color.White; foreach (TableCell cell in row.Cells) { if (row.RowIndex % 2 == 0) { cell.BackColor = GridView4.AlternatingRowStyle.BackColor; } else { cell.BackColor = GridView4.RowStyle.BackColor; } cell.CssClass = "textmode"; } } GridView4.RenderControl(hw); //style to format numbers to string string style = @" .textmode { } "; Response.Write(style); Response.Output.Write(sw.ToString()); Response.Flush(); Response.End(); } //Display message InfoPanel.Visible = true; InfoPanel.CssClass = "panel panel-success"; lblMessage.CssClass = "text text-sucess bold"; lblMessage.Text = "File has been exported!"; } catch (Exception ex) { //Display message InfoPanel.Visible = true; lblMessage.Text = "An error has occurred. Please try again later!
" + ex.Message; lblMessage.CssClass = "text text-danger bold"; InfoPanel.CssClass = "panel panel-danger"; panelResult.Visible = false; } }

Excel .xls文件中的结果很好(没有样式除了标题列,没有页脚,就像Gridview上显示的那样):

在此处输入图像描述


我正在寻找另一种方法来避免这种警告,所以我看到人们喜欢使用
ClosedXML ,所以我用这个事件替换上面的那个事件:

 protected void ExportExcel(object sender, EventArgs e) { DataTable dt = new DataTable("GridView_Data"); foreach(TableCell cell in GridView4.HeaderRow.Cells) { dt.Columns.Add(cell.Text); } foreach (GridViewRow row in GridView4.Rows) { dt.Rows.Add(); for (int i=0; i<row.Cells.Count; i++) { dt.Rows[dt.Rows.Count - 1][i] = row.Cells[i].Text; } } using (XLWorkbook wb = new XLWorkbook()) { wb.Worksheets.Add(dt); Response.Clear(); Response.Buffer = true; Response.Charset = ""; Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; Response.AddHeader("content-disposition", "attachment;filename=GV.xlsx"); using (MemoryStream MyMemoryStream = new MemoryStream()) { wb.SaveAs(MyMemoryStream); MyMemoryStream.WriteTo(Response.OutputStream); Response.Flush(); Response.End(); } } } 

结果很糟糕(唯一好的是导出的文件是一个真正的2007+ Excel表,所以没有警告): 在此处输入图像描述

如何使用closedXML获得上面的“好”结果?

第二部分代码(使用ClosedXML)的主要问题是,您正在尝试将GridViewRow Text属性用于TemplateField字段列。 正如您在此处所见,您可以通过Text属性仅为BoundField字段列和自动生成的字段列获取字段值。

要从TemplateField获取值,您应该导航到包含值并从中获取值的内部控件。

如果您有以下列模板:

       

你的代码应该是:

  for (int i=0; i 

编辑

您的代码应如下所示:

 protected void ExportExcel(object sender, EventArgs e) { DataTable dt = new DataTable("GridView_Data"); foreach (DataControlField col in GridView4.Columns) { dt.Columns.Add(col.HeaderText); } foreach (GridViewRow row in GridView4.Rows) { dt.Rows.Add(); for (int i = 0; i < row.Cells.Count; i++) { dt.Rows[dt.Rows.Count - 1][i] = (FindControl(row.Cells[i].Controls, "lbl") as Label).Text; } } //your code below is not changed } protected Control FindControl(ControlCollection collection, string id) { foreach (Control ctrl in collection) { if (ctrl.ID == id) return ctrl; } return null; } 

确保TemplateField使用的所有Label控件都具有与"lbl"相同的ID

                 

我试过它的工作,请找代码希望它能帮到你:

的Index.aspx

  <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="ExportExcel.Index" %>       

Index.aspx.cs

  using ClosedXML.Excel; using System; using System.Collections.Generic; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace ExportExcel { public partial class Index : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (!this.IsPostBack) { GetData(); } } private void GetData() { DataTable dt = new DataTable(); dt.Columns.AddRange(new DataColumn[3] { new DataColumn("Id", typeof(int)), new DataColumn("Name", typeof(string)), new DataColumn("Country", typeof(string)) }); dt.Rows.Add(1, "abc", "UK"); dt.Rows.Add(2, "def", "India"); dt.Rows.Add(3, "ghi", "France"); dt.Rows.Add(4, "jkl", "Russia"); GridView1.DataSource = dt; GridView1.DataBind(); } protected void btnExport_Click(object sender, EventArgs e) { try { DataTable dt = new DataTable("GridView_Data"); foreach (TableCell cell in GridView1.HeaderRow.Cells) { dt.Columns.Add(cell.Text); } foreach (GridViewRow row in GridView1.Rows) { TextBox txtNameRow = (TextBox)row.FindControl("txtName"); Label lblCountryRow = (Label)row.FindControl("lblCountry"); DataRow drow = dt.NewRow(); for (int i = 0; i < GridView1.Columns.Count; i++) { drow[i] = row.Cells[i].Text; } drow["Name"] = txtNameRow.Text; drow["Country"] = lblCountryRow.Text; dt.Rows.Add(drow); } using (XLWorkbook wb = new XLWorkbook()) { wb.Worksheets.Add(dt); Response.Clear(); Response.Buffer = true; Response.Charset = ""; Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; Response.AddHeader("content-disposition", "attachment;filename=GV.xlsx"); using (MemoryStream MyMemoryStream = new MemoryStream()) { wb.SaveAs(MyMemoryStream); MyMemoryStream.WriteTo(Response.OutputStream); Response.Flush(); Response.End(); } } } catch (Exception ex) { throw; } } } } 

我在按钮单击事件上调用导出到Excel,如下所示

 protected void btnPrint_Click(object sender, EventArgs e) { fileName = string.Format(fileName, DateTime.Now.ToString("MMddyyyy_hhmmss")); Extensions.ExportToXcel_SomeReport(dt, fileName, this.Page); } 

从那里我有一个名为Extensions的utils类,我在ExportToExcel_SomeReport定义了ExportToExcel_SomeReport方法

 public static class Extensions { internal static void ExportToXcel_SomeReport(DataTable dt, string fileName, Page page) { var recCount = dt.Rows.Count; RemoveHtmlSpecialChars(dt); fileName = string.Format(fileName, DateTime.Now.ToString("MMddyyyy_hhmmss")); var xlsx = new XLWorkbook(); var ws = xlsx.Worksheets.Add("Some Report Name"); ws.Style.Font.Bold = true; ws.Cell("C5").Value = "YOUR REPORT NAME"; ws.Cell("C5").Style.Font.FontColor = XLColor.Black; ws.Cell("C5").Style.Font.SetFontSize(16.0); ws.Cell("E5").Value = DateTime.Now.ToString("MM/dd/yyyy HH:mm"); ws.Range("C5:E5").Style.Font.SetFontSize(16.0); ws.Cell("A7").Value = string.Format("{0} Records", recCount); ws.Style.Font.Bold = false; ws.Cell(9, 1).InsertTable(dt.AsEnumerable()); ws.Row(9).InsertRowsBelow(1); // ws.Style.Font.FontColor = XLColor.Gray; ws.Columns("1-9").AdjustToContents(); ws.Tables.Table(0).ShowAutoFilter = true; ws.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; DynaGenExcelFile(fileName, page, xlsx); } ///  /// Remove all HTML special characters from datatable field if they are present ///  ///  private static void RemoveHtmlSpecialChars(DataTable dt) { for (int rows = 0; rows < dt.Rows.Count; rows++) { for (int column = 0; column < dt.Columns.Count; column++) { dt.Rows[rows][column] = dt.Rows[rows][column].ToString().Replace(" ", string.Empty); } } } ///  /// Call this Method to Generate the Excel Files from different Lap Reports depending on which one has been selected ///  ///  ///  ///  private static void DynaGenExcelFile(string fileName, Page page, XLWorkbook xlsx) { page.Response.ClearContent(); page.Response.ClearHeaders(); page.Response.ContentType = "application/vnd.ms-excel"; page.Response.AppendHeader("Content-Disposition", string.Format("attachment;filename={0}.xlsx", fileName)); using (MemoryStream memoryStream = new MemoryStream()) { xlsx.SaveAs(memoryStream); memoryStream.WriteTo(page.Response.OutputStream); } page.Response.Flush(); page.Response.End(); } } 

与流行的看法相反,您可以将文件的扩展名设置为.html,Excel可以将其打开。

在此处输入图像描述

只需将扩展名设置为HTML:

 Response.AddHeader("content-disposition", "attachment;filename=GV.html"); 

并保留Excel作为内容类型:

 Response.ContentType = "application/ms-excel"; 

编辑:哦,对,忘了提,这应该让烦人的对话消失。

编辑2:看起来原来的问题已经改变了…现在它正在谈论使用ClosedXML ……但我会在这里留下这个答案,以防其他人使用HTML和Excel。