2011年7月14日 星期四

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解決。(可以參考這篇文章中的【技術細節】一欄)

沒有留言:

張貼留言