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等东西了,只有这样才能抓住本质,深刻理会;同时不易犯错,程序才能高效稳定,程序员也能省省心,提高效率!


  • 相关阅读:
    ural(Timus) 1019 Line Painting
    ACMICPC Live Archive 2031 Dance Dance Revolution
    poj 3321 Apple Tree
    其他OJ 树型DP 选课
    poj 3548 Restoring the digits
    ACMICPC Live Archive 3031 Cable TV Network
    递归循环获取指定节点下面的所有子节点
    手动触发asp.net页面验证控件事件
    子级Repeater获取父级Repeater绑定项的值
    没有列名的数据绑定
  • 原文地址:https://www.cnblogs.com/nlh774/p/3460264.html
Copyright © 2011-2022 走看看