zoukankan      html  css  js  c++  java
  • ASP.NET网页生成EXCEL并下载(利用DataGrid或GridView等)

    前几天要在后台查询数据库内容(用entity framework),将查询出来的信息(List或DataTable形式)转成EXCEL供用户下载。经过谷歌、百度搜索,终于搜出了一些代码。似乎可用了,结果问题一大堆。

    /// <summary>
        /// 下载EXCEL
        /// </summary>
        /// <param name="dt">数据</param>
        /// <param name="fileName">下载的EXCEL文件名</param>
        public static void OutputToExcelGB2312(object dt, string fileName)
        {
            if (dt != null)
            {
                // 获取当前会话,并设置当前会话中Response的相关属性,让输出内容输出到文件中。
                System.Web.HttpContext curContext = System.Web.HttpContext.Current;
                curContext.Response.Charset = "GB2312";
                curContext.Response.ContentEncoding = System.Text.Encoding.GetEncoding("GB2312");
                curContext.Response.AddHeader("content-disposition", "attachment;filename="
                 + System.Web.HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8) + ".xls");
                curContext.Response.ContentType = "application/ms-excel";
    
                //将要导出的数据绑定到DataGrid控件上
                System.Web.UI.WebControls.DataGrid dgExport = new System.Web.UI.WebControls.DataGrid();
                dgExport.DataSource = dt;
                dgExport.AllowPaging = false;
                dgExport.DataBind();
                //创建输出流用来保存输出内容
                System.IO.StringWriter strWriter = new System.IO.StringWriter();
                System.Web.UI.HtmlTextWriter htmlWriter = new System.Web.UI.HtmlTextWriter(strWriter);
    
                //将DataGrid控件的内容输出到流中。
                dgExport.RenderControl(htmlWriter);
                
                curContext.Response.Write(strWriter.ToString());
                curContext.Response.End();
            }
        }
    View Code

    参数为DataTable形式的数据和str文件名。这个函数主要意思是利用dataGrid这类控件生成行列信息,最终转至EXCEL类型。

    但这个函数通用性不好,因为我用entity framework或者LINQ查出来的数据大多是List或IEnumable泛型形式的,不便转换成DataTable形式(其实可以转,就是定义个DataTable dt;添加列名,最后定义行并填充数据,最后提交dt即可),是在麻烦,特别是列数据一多,代码杂糅,很是不爽。

    我想, dataGrid这类控件不是有根据数据源自动生成列及填充数据项的功能吗?!那我就不用手动做DataTable定义列并赋值行了,让dataGrid自动生成吧!

    MSDN上关于DataGrid或GridView这类控件的DataSource属性是这么说明的:

    “使用 DataSource 属性指定要绑定到数据列表控件的值的源。 数据源必须是实现 System.Collections .IEnumerable 接口(例如 System.Data .DataView System.Collections .ArrayList System.Collections .Hashtable )或 IListSource 接口的对象,才能绑定到从 BaseDataList 类派生的控件。 在设置 DataSource

    必须手动编写代码才能执行数据绑定。”

    也就是说,只要数据源(object形式)支持IEnumerable迭代,那控件就可以根据数据源自动生成列、填充行数据等。既然如此,我用entity framework或者LINQ查出的List或IEnumable泛型形式的数据当然可以生成啦!

    下面把上述方法稍改造下,使之可以支持任意IEnumable接口的数据源:

     1  /// <summary>
     2     /// 下载EXCEL
     3     /// </summary>
     4     /// <param name="dt">数据</param>
     5     /// <param name="fileName">下载的EXCEL文件名</param>
     6     public static void OutputToExcelGB2312(object dt, string fileName)
     7     {
     8         if (dt != null)
     9         {
    10             // 获取当前会话,并设置当前会话中Response的相关属性,让输出内容输出到文件中。
    11             System.Web.HttpContext curContext = System.Web.HttpContext.Current;
    12             curContext.Response.Charset = "GB2312";
    13             curContext.Response.ContentEncoding = System.Text.Encoding.GetEncoding("GB2312");
    14             curContext.Response.AddHeader("content-disposition", "attachment;filename="
    15              + System.Web.HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8) + ".xls");
    16             curContext.Response.ContentType = "application/ms-excel";
    17 
    18             //将要导出的数据绑定到DataGrid控件上
    19             System.Web.UI.WebControls.DataGrid dgExport = new System.Web.UI.WebControls.DataGrid();
    20             dgExport.DataSource = dt;
    21             dgExport.AllowPaging = false;
    22             dgExport.DataBind();
    23             //创建输出流用来保存输出内容
    24             System.IO.StringWriter strWriter = new System.IO.StringWriter();
    25             System.Web.UI.HtmlTextWriter htmlWriter = new System.Web.UI.HtmlTextWriter(strWriter);
    26 
    27             //将DataGrid控件的内容输出到流中。
    28             dgExport.RenderControl(htmlWriter);
    29             
    30             curContext.Response.Write(strWriter.ToString());
    31             curContext.Response.End();
    32         }
    33     }

    这样一些,清爽多了。

    写个例子吧,各位如果有幸看到这些代码,算是抛砖引玉,给予启发了。

    1.新建ASP.NET项目。加个窗体,在后台写代码,为了方便就在Page_Load()方法里写代码了。

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Web;
     5 using System.Web.UI;
     6 using System.Web.UI.WebControls;
     7 public class Info
     8 {
     9     public int a { get; set; }
    10     public Nullable<int> b { get; set; }
    11 
    12 }
    13 public partial class ExcelTest : System.Web.UI.Page
    14 {
    15     protected void Page_Load(object sender, EventArgs e)
    16     {
    17         Info i = new Info() { a = 1, b = 1 };
    18         Info j = new Info() { a = 2, b = 2 };
    19         List<Info> l = new List<Info>() { i, j };
    20         OutputToExcelGB2312(l, "test");
    21 
    22         //DataGrid1.DataSource = l;
    23         //DataGrid1.DataBind();
    24     }
    25 }

    浏览运行,跳出下载对话框,下载EXCEL。以为大功告成,结果:

    见鬼!!!!!只有只有列a,列b哪去了?!!!

    多次调试,确认问题在OutputToExcelGB2312()方法里:

    1         System.Web.UI.WebControls.DataGrid dgExport = new System.Web.UI.WebControls.DataGrid();
    2             dgExport.DataSource = dt;
    3             dgExport.AllowPaging = false;
    4             dgExport.DataBind();  //查看属性的值,这时自动生成的列数是1,及 a,没有b.

    我当时一时难理解,为什么?!突然瞥见我查数据库信息是有的信息是int?及Nullable<int>类型的。这ORM关系(entity framework,linq)很常见,因为数据库里有些字段是可以为空的,这些字段ORM转换后就成为了Nullable<T>类型。

    在这个例子里就是数据项类型是:

    public Nullable<int> b { get; set; }

    难道是dataGrid不识别Nullable<int>?!果断换个声明
    public int b { get; set; }
    就这样,问题解决了。。。。

    不过,我依然只知大概,不知为什么(内部绑定原理比较复杂).应该有反射、动态绑定、IEnumable、数据项生成等知识吧。
    大家可以百度谷歌下,例如以下资料:http://kb.cnblogs.com/kb/70077/

    个人理解dataGrid是.NET1.0就有的东西,那时Nullable类型还没有出现,所以可能不认识(dadaGrid向后兼容有点问题吧)
    基于此,我想到还有另外一种方法,在OutputToExcelGB2312()中将dataGrid改成GridView,这样Gridview就认识Nullable类型,当然就可以实现了(但是Gridview会对bool等类型转换
    ,成为checkBox类型。)有点自作主张了,最后转化为EXCEL时里面就会存在checkBox,原数据为true则打钩,false则不打勾。

    .NET细节隐藏的太好,新手入门很简单,拖拖控件即可。但开源的东西较少,有时用的多了真是迷糊了,不知内部到底怎么实现的,结果错漏摆出。哎!!看来要好好学习了,适当研究研究内部源码。
    包括C#,CLR,IL等东西了,只有这样才能抓住本质,深刻理会;同时不易犯错,程序才能高效稳定,程序员也能省省心,提高效率!


  • 相关阅读:
    shell脚本修改Linux系统中所有IP样例
    关闭并卸载数据库脚本
    查询编译不通过的存储过程并重新编译
    SQL函数造数据样例(一)
    类型转换和多态
    Java学习笔记(三)
    Java学习笔记二()
    Java学习笔记(一)
    1.2.零宽断言
    1.3.匹配小括号的字符(可能有小括号在一行的,也有多行的)
  • 原文地址:https://www.cnblogs.com/nlh774/p/3460264.html
Copyright © 2011-2022 走看看