TIPS-Export GridView To Excel

辛辛苦苦幫User寫了GridView或DataGrid網頁,User常會神來一筆: 我想把這個清單轉成Excel耶~~~

簡單! Mouse拖曳選取、Ctrl-C複製、開啟Excel、Ctrl-V貼上不就OK啦!

很不幸地,每次提供這種建議都會招來User白眼。User要是這麼愛自己DIY,IT人員一年大概可以多放十天年假吧!? 而且還有一個大問題,Grid常會設自動分頁,要User剪剪貼貼之餘還要順便玩一下"接龍",並不合情理。

過去我搞過一些鋸箭解決方案: 用foreach DataTable中的每一個Row,再Response.Write成CSV;再不然就是寫成Reporting Service報表,借重它輸出成Excel功能。

但這二個方法都有些缺點,前者會因為轉成CSV會喪失格式設計,後者則得在做好DataGrid/GridView後,再另外做一張報表並建立Reporting Service機制,同時,二者都得在GridView/DataGrid外多花功夫。如果GridView可以直接輸出成Excel,該有多好?

再度碰到這個需求,這回我Google了一下,才發現已經有許多人找到直接匯出的解決方案囉!

利用GridView自行Render出與網頁上格式相同的HTML,配合application/vnd.xls MIME Type,GridView就可以直接在Excel中重現,很酷吧?

protected void btnExportExcel_Click(object sender, EventArgs e)
{
    Response.Clear();
    Response.AddHeader("content-disposition", 
        "attachment;filename=PoolExport.xls");
    Response.ContentType = "application/vnd.xls";
    System.IO.StringWriter sw = new System.IO.StringWriter();
    System.Web.UI.HtmlTextWriter htw = new HtmlTextWriter(sw);
 
    //關閉換頁跟排序
    GridView1.AllowSorting = false;
    GridView1.AllowPaging = false;
    
    //移去不要的欄位
    GridView1.Columns.RemoveAt(GridView1.Columns.Count - 1);
    GridView1.DataBind();
 
    //建立假HtmlForm避免以下錯誤
    //Control 'GridView1' of type 'GridView' must be placed inside 
    //a form tag with runat=server. 
    //另一種做法是override VerifyRenderingInServerForm後不做任何事
    //這樣就可以直接GridView1.RenderControl(htw);
 
    HtmlForm hf = new HtmlForm();
    Controls.Add(hf);
    hf.Controls.Add(GridView1);
    hf.RenderControl(htw);
 
    Response.Write(sw.ToString());
    Response.End();
}

補充說明幾個重點:

  1. 由於是透過HTML+MIME宣告的原理,DataGrid、GridView都適用。
  2. 記得移去不要的欄位,取消排序、分頁的設定。
  3. 這個寫法會產生Control 'GridView1' of type 'GridView' must be placed inside a form tag with runat=server的錯誤,可利用override VerifyRenderingInServerForm或另建一個假的HtmlForm來避免
  4. 這個寫法還會導致RegisterForEventValidation can only be called during Render()的錯誤,需在Page宣告中停用EnableEventValidation解決。(可以參考這篇文章中的【技術細節】一欄)

Published 03 October 2007 01:29 AM 由 Jeffrey
Filed under: ,


意見

# Frank said on 09 November, 2007 04:24 AM

我也用這方法從網頁DataGrid產生excel,但如果資料筆數太多等待時間會成指數性成長,只有20筆大概等兩秒,500筆要等到7分鐘,想請教Jeffrey大大有遇過類似的問題嗎?

# evakey said on 13 December, 2007 05:56 AM

我在 GridView1.RenderControl(htw); 之前使用

GridView1.EnableViewState = false;

就不會有 Control 'GridView1' of type 'GridView' must be placed inside     //a form tag with runat=server. 的錯誤,但不是很肯定,請你試試囉

# Jeffrey said on 13 December, 2007 02:32 PM

To evakey, 在ASP.NET 2.0測試了一下,沒有成功... 如果還有其他情報,歡迎再提供給我。謝謝!

# evakey said on 13 December, 2007 05:08 PM

今早再試,發現使用 EnableViewState = false; 的確有效,但如果在 PostBack 後再關閉,似乎來不及…

有什麼方法可以清除 GridView 的 ViewState 呢?

再來試試~

# evakey said on 13 December, 2007 07:00 PM

重新整理兩個方法(註:我使用的是 DataGrid)

1. 因為我的查詢結果含有排序功能所以存成 Excel 時要先關閉 AllowSorting 功能(不然會有連結,醜),然後需要再 DataBind 一次。而在 DataBind 之前使用 EnableViewState = false; 即可避免「Control 'GridView1' of type 'GridView' must be placed inside a form tag with runat=server. 」的錯誤

2. 另一個方法於 blog.csdn.net/.../1282106.aspx 所發現

只要加上

public override void VerifyRenderingInServerForm(Control control)

{

   //避免「型別 xxx 的控制項 xxx 必須置於有 runat=server 的表單標記之中。」的問題

}

即可

不知道這兩個方法有何優缺點…

# ettore@e-cefala.it said on 22 December, 2007 11:17 AM

try http://www.gridviewtoexcel.com that's a real XML and xlsx export to Excel

# devin said on 17 January, 2008 12:47 AM

Excel可辨認HTML組成的Table

匯出的Excel可用記事本開啟.

不過在存成Excel後,編碼就成了Excel的編碼嚕 :)

在vs2003

匯出後,另存新檔時,會預設格式為HTML

Office 2000 下測試

# joe said on 15 October, 2008 03:54 AM

請問大大 若要將GridView 產生的EXECL檔 自動轉存在特定的目錄中 要如何實作? 謝謝

# Jeffrey said on 15 October, 2008 07:00 AM

to joe, "自動轉存"的理想並不容易實現,企圖用Javascript/Flash/Silverlight等技術在未經使用者同意(也就是使用者不必進行任何操作),就將檔案存入使用者本機,會嚴重違反瀏覽器的安全原則。想突破此一限制大概只能靠客製ActiveX Control或撰寫Plug-In才做得到,不過得說服使用者願意安裝你的元件/程式才行。

# 戰鬥大貓 said on 30 November, 2008 08:50 PM

感謝,正好有這個需求要處理,馬上來試試看!

# Frances said on 09 February, 2009 12:30 AM

請問可以分別存在多個sheet裡嗎??

# Jeffrey said on 09 February, 2009 03:27 AM

to Frances, 據我所知,這種產生HTML再標ContentType的方法只能產生單一Sheet,如果有人知道解決方案請再出個聲。

# Pamela said on 17 February, 2009 12:39 AM

想要請問一下,照著大大的做法做了,為何我在所匯出的Excel會出現不只GridView,還包含了Web上的其他欄位

找了好久,真的不知道為什麼?!

# Jeffrey said on 17 February, 2009 12:57 AM

to Pamela, 這段程式中,以Response.Clear()起始,以Response.Write(); Response.End()結尾,理論上應該只有我們輸出的內容而已,我想不太出哪裡可以被加料... 莫非是HttpModule、HttpHandler或Control Adpater之類的機制在作怪?

# Chenyy said on 19 February, 2009 08:24 PM

我的情形跟Pamela兄很類似,在匯出成Excel時最上面會出現空行XD,後來發現New出來的HtmlForm會有一些script跟Viewstate及Hidden欄位等資訊.

改用override VerifyRenderingInServerForm方式的格式才比較正常.

# Hans said on 18 April, 2009 10:38 AM

以Response.Clear()起始,Response.Write()和 Response.End()結尾方法导出Excel文件时,如何可以向"btnExportExcel_Click"所在页面输入脚本呢?似乎用这个方法就无法输出JS脚本给页面以提示Excel已生成.

# Jeffrey said on 20 April, 2009 10:26 PM

to Hans, 關於"输出JS脚本给页面以提示Excel已生成",我想到的解法是傳回一個Web跑JS,再用Iframe或window.open導到下載。不過,下載時,User就會被提示需要開啟或另存檔案,我覺得似乎不太需要額外的alert提示。

# karen said on 14 May, 2009 01:00 AM

請問為什麼匯出成Excel 後,檔案會預設格式為HTML,要如何改成檔案格式為excel(.xls)?

# Jeffrey said on 14 May, 2009 09:08 AM

to karen, 是指Browser/IE開啟時當成HTML開啟? 理論上設為Response.ContentType = "application/vnd.xls";後應該就會被視為xls,以Excel開啟才對。要再提供更詳細的訊息給大家嗎?

# Karen said on 24 July, 2009 03:21 AM

我匯出的Excel可以開啟 可是會出現檔案格式與附檔名格式不同的訊息 有辦法不要show出這個訊息嗎??(我是用excel2007開啟的)

# Jeffrey said on 24 July, 2009 08:51 AM

to Karen, 是的,我也發現Excel 2007開啟時會多了這個警示,到截稿為止,我還沒找到閃掉的方法。

# 大估 said on 06 December, 2009 08:56 PM

小弟最近的案子,有關匯出excel的部份,開始轉用NPOI的元件來處理,詳細說明:msdn.microsoft.com/.../ee818993.aspx

在此給大家作另一個解法參考~

# No.18 said on 26 January, 2010 09:28 AM

黑暗大:

不好意思借轉一下本篇url在小鋪上

已有註明是來自黑暗的範例

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 

請輸入以上的數字:

搜尋

Go

<October 2007>
SunMonTueWedThuFriSat
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910
 
RSS
【工商服務】

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


BlogLook Score and Rank

Syndication