將一個DataGrid匯到一個Excel內很簡單,但要如何將多個DataGrid滙到同一個Excel內,並分別放在不同的Worksheet工作表內.
Asp.net匯出一個DataGrid到Excel的方式很簡單,只要執行以下幾行就可以達成,
Response.Clear();
Response.Buffer = true;
Response.Charset = "";
Response.AddHeader("content-disposition", "attachment;filename=FileName.xls");
Response.ContentEncoding = Encoding.GetEncoding( "big5" );
Response.ContentType = "application/vnd.ms-excel";
this.EnableViewState = false;
StringWriter sw=new StringWriter();
HtmlTextWriter htw=new HtmlTextWriter(sw);
DataGrid1.RenderControl(htw);
Response.Write( sw.ToString());
Response.End();但如果有多個DataGrid,希望能匯到同一個Excel檔,但要分別放到不同的Worksheet工作表內,這樣的方式就無法達成,需要做點加工才可以,就最近的實驗結果,有兩個方法可以達成,一個是可以透過DataSet將它匯出,另一種就是直接用DataGrid.RenderControl去做,這次先以DataGrid.RenderControl的方式來說.
這次所用到的是MIME的方式,匯出來的Excel格式如下:
X-Document-Type: Workbook
Content-Type: multipart/related; boundary="-=BOUNDARY_EXCEL"
---=BOUNDARY_EXCEL
Content-Type: text/html; charset="big5"
<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel">
<head>
<xml>
<o:DocumentProperties>
<o:Author>Jeff_Yeh</o:Author>
<o:LastAuthor>Jeff_Yeh</o:LastAuthor>
<o:Created>2009/9/2 下午 09:00:48</o:Created>
<o:LastSaved>2009/9/2 下午 09:00:48</o:LastSaved>
<o:Company>Jeff隨手記</o:Company>
<o:Version>11.5606</o:Version>
</o:DocumentProperties>
</xml>
<xml>
<x:ExcelWorkbook>
<x:ExcelWorksheets>
<x:ExcelWorksheet>
<x:Name>TestA</x:Name>
<x:WorksheetSource HRef="cid:9d6e5d0b-f362-497b-9ef6-a0e36ae8c4c5"/>
</x:ExcelWorksheet>
<x:ExcelWorksheet>
<x:Name>TestB</x:Name>
<x:WorksheetSource HRef="cid:94c5e9ba-4bec-4bb6-9fe6-8e0c160b6c1b"/>
</x:ExcelWorksheet>
</x:ExcelWorksheets>
</x:ExcelWorkbook>
</xml>
</head>
</html>
---=BOUNDARY_EXCEL
Content-ID: 9d6e5d0b-f362-497b-9ef6-a0e36ae8c4c5
Content-Type: text/html; charset="big5"
<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel">
<head>
<xml>
<x:WorksheetOptions>
<x:ProtectContents>False</x:ProtectContents>
<x:ProtectObjects>False</x:ProtectObjects>
<x:ProtectScenarios>False</x:ProtectScenarios>
</x:WorksheetOptions>
</xml>
</head>
<body>
<table cellspacing="0" rules="all" border="1" id="DataGrid1" style="border-collapse:collapse;">
<tr>
<td>aa</td><td>bb</td>
</tr><tr>
<td>0</td><td>2009/9/2 下午 09:00:48</td>
</tr><tr>
<td>1</td><td>2009/9/2 下午 09:00:48</td>
</tr><tr>
<td>2</td><td>2009/9/2 下午 09:00:48</td>
</tr><tr>
<td>3</td><td>2009/9/2 下午 09:00:48</td>
</tr><tr>
<td>4</td><td>2009/9/2 下午 09:00:48</td>
</tr><tr>
<td>5</td><td>2009/9/2 下午 09:00:48</td>
</tr><tr>
<td>6</td><td>2009/9/2 下午 09:00:48</td>
</tr><tr>
<td>7</td><td>2009/9/2 下午 09:00:48</td>
</tr><tr>
<td>8</td><td>2009/9/2 下午 09:00:48</td>
</tr><tr>
<td>9</td><td>2009/9/2 下午 09:00:48</td>
</tr>
</table></body>
</html>
---=BOUNDARY_EXCEL
Content-ID: 94c5e9ba-4bec-4bb6-9fe6-8e0c160b6c1b
Content-Type: text/html; charset="big5"
<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel">
<head>
<xml>
<x:WorksheetOptions>
<x:ProtectContents>False</x:ProtectContents>
<x:ProtectObjects>False</x:ProtectObjects>
<x:ProtectScenarios>False</x:ProtectScenarios>
</x:WorksheetOptions>
</xml>
</head>
<body>
<table cellspacing="0" rules="all" border="1" id="DataGrid2" style="border-collapse:collapse;">
<tr>
<td>cc</td><td>dd</td>
</tr><tr>
<td>0</td><td>2009/9/2 下午 09:00:48</td>
</tr><tr>
<td>1</td><td>2009/9/2 下午 09:00:48</td>
</tr><tr>
<td>2</td><td>2009/9/2 下午 09:00:48</td>
</tr><tr>
<td>3</td><td>2009/9/2 下午 09:00:48</td>
</tr><tr>
<td>4</td><td>2009/9/2 下午 09:00:48</td>
</tr><tr>
<td>5</td><td>2009/9/2 下午 09:00:48</td>
</tr><tr>
<td>6</td><td>2009/9/2 下午 09:00:48</td>
</tr><tr>
<td>7</td><td>2009/9/2 下午 09:00:48</td>
</tr><tr>
<td>8</td><td>2009/9/2 下午 09:00:48</td>
</tr><tr>
<td>9</td><td>2009/9/2 下午 09:00:48</td>
</tr>
</table></body>
</html>
---=BOUNDARY_EXCEL--
只要把上列複制另存為xls檔,就可以開的起來,在裡面就可以看到兩個worksheet,但這樣密密麻麻的東西,還真是看到眼花,而冃Content-ID還必需對應到Worksheep的 HRef的cid,不然Excel就會無法開啟,所以花了一點時間寫了一個Class來呼叫,就不用管那麼多東西.
public class ExcelUtil002
{003
string _Author;004
string _Company;005

006 StringBuilder sbBody=new StringBuilder();
007
StringBuilder sbSheet=new StringBuilder();008
public ExcelUtil(string Author,string Company)009
{010
_Author=Author;011
_Company=Company;012
sbBody.AppendFormat(013
"MIME-Version: 1.0\r\n"+014
"X-Document-Type: Workbook\r\n"+015
"Content-Type: multipart/related; boundary=\"-=BOUNDARY_EXCEL\"\r\n\r\n"+016
"---=BOUNDARY_EXCEL\r\n"+017
"Content-Type: text/html; charset=\"big5\"\r\n\r\n"+018
"<html xmlns:o=\"urn:schemas-microsoft-com:office:office\"\r\n"+019
"xmlns:x=\"urn:schemas-microsoft-com:office:excel\">\r\n\r\n"+020
"<head>\r\n"+021
"<xml>\r\n"+022
"<o:DocumentProperties>\r\n"+023
"<o:Author>{0}</o:Author>\r\n"+024
"<o:LastAuthor>{0}</o:LastAuthor>\r\n"+025
"<o:Created>{1}</o:Created>\r\n"+026
"<o:LastSaved>{1}</o:LastSaved>\r\n"+027
"<o:Company>{2}</o:Company>\r\n"+028
"<o:Version>11.5606</o:Version>\r\n"+029
"</o:DocumentProperties>\r\n"+030
"</xml>\r\n"+031
"<xml>\r\n"+032
"<x:ExcelWorkbook>\r\n"+033
"<x:ExcelWorksheets>\r\n"034
,_Author035
,DateTime.Now.ToString()036
,_Company);037
}038

039 private string ExportExcel()
040
{041
StringBuilder sb=new StringBuilder(sbBody.ToString());042
043
sb.Append("</x:ExcelWorksheets>\r\n"+044
"</x:ExcelWorkbook>\r\n"+045
"</xml>\r\n"+046
"</head>\r\n"+047
"</html>\r\n\r\n");048
049
sb.Append(sbSheet.ToString());050

051 sb.Append("---=BOUNDARY_EXCEL--");
052
053
return sb.ToString();054
}055

056 public void AddGrid(DataGrid grid,string sheetName)
057
{058
string gid=Guid.NewGuid().ToString();059
sbBody.AppendFormat("<x:ExcelWorksheet>\r\n"+060
"<x:Name>{0}</x:Name>\r\n"+061
"<x:WorksheetSource HRef=\"cid:{1}\"/>\r\n"+062
"</x:ExcelWorksheet>\r\n"063
,sheetName.Replace(":","").Replace("\\","").Replace("/","").Replace("?","").Replace("*","").Replace("[","").Replace("]","").Trim()064
,gid);065
066
StringWriter sw=new StringWriter();067
HtmlTextWriter htw=new HtmlTextWriter(sw);068
grid.RenderControl(htw);069

070 sbSheet.AppendFormat("---=BOUNDARY_EXCEL\r\n"+
071
"Content-ID: {0}\r\n"+072
"Content-Type: text/html; charset=\"big5\"\r\n\r\n"+073
"<html xmlns:o=\"urn:schemas-microsoft-com:office:office\"\r\n"+074
"xmlns:x=\"urn:schemas-microsoft-com:office:excel\">\r\n\r\n"+075
"<head>\r\n"+076
"<xml>\r\n"+077
"<x:WorksheetOptions>\r\n"+078
"<x:ProtectContents>False</x:ProtectContents>\r\n"+079
"<x:ProtectObjects>False</x:ProtectObjects>\r\n"+080
"<x:ProtectScenarios>False</x:ProtectScenarios>\r\n"+081
"</x:WorksheetOptions>\r\n"+082
"</xml>\r\n"+083
"</head>\r\n"+084
"<body>\r\n"085
,gid); 086
sbSheet.Append(sw.ToString());087
sbSheet.Append("</body>\r\n"+088
"</html>\r\n\r\n");089
sw.Close();090
htw.Close();091
}092

093 public void Export(Page page,string FileName)
094
{095
page.Response.Clear();096
page.Response.Buffer = true;097
page.Response.Charset = "";098
page.Response.AddHeader("content-disposition", string.Format("attachment;filename={0}.xls",FileName));099
page.Response.ContentEncoding = Encoding.GetEncoding( "big5" );100
page.Response.ContentType = "application/vnd.ms-excel";101
page.Response.Write(ExportExcel());102
page.Response.End();103
}104

105 public void Clear()
106
{107
sbBody.Remove(0,sbBody.Length);108
sbSheet.Remove(0,sbBody.Length);109
}110
}
看起來程式碼也不多,但就可以少寫很多Code,比如來說,我要將DataGrid1跟DataGrid2分別滙到不同的worksheet裡去,我只要寫以下的Code就好.
*第63行看我Replace了幾個符號 : \ / ? * [ ] , 因為這幾個符號是保留字,如果使用到,worksheet工作表的名稱就會變為 復原_Sheet1,這是Excel本身的限制.我沒判斷長度及空字串~~
ExcelUtil eu=new ExcelUtil("Jeff_Yeh","Jeff隨手記");2
eu.AddGrid(DataGrid1,"TestA");3
eu.AddGrid(DataGrid2,"TestB");4
eu.Export(this,"Jeff");第一行就是使用上面Sample Class,ExceUtil,傳入兩個參數,第一個是作業,第二個是公司行號,這樣在看Excel摘要資訊時,就可以看到.
第二,三行就是把DataGrid傳給ExcelUtil去處理,第一個參數是DataGrid,第二個參數是Worksheet工作表的名稱.
第四行就是匯出Excel檔,第一個參數是Page,第二個參數是匯出的檔案名稱.
所以每加一個DataGrid,就呼叫一次AddGrid就好,其它的都不用管.
參考資訊 :
如何將不同的GridView匯出到不同的EXCEL sheet中
原始碼下載 :
