告别ASP.NET操作EXCEL的烦恼
公元19XX年前,關于EXCEL的操作就如滔滔江水,連綿不絕,真正操作EXCEL我也是從去年下半年開始的,有些比較復雜的年度報表之類的,做起來也有點費力,不過還是都能畫出來了,關于EXCEL的報表導出,考慮到導出耗時的問題我主要采用AJAX來做的,分別捕捉幾個起止狀態,給客戶端提示3個狀態:正在檢索數據。。。---》準備導出數據。。。(只是從數據庫成功取出,還沒有讀寫excel文件)--》正在讀寫文件--》導出數據成功,當然如果哪一過程出錯,都有對應的提示,只所以想到寫這篇文章,主要是因為今年有個系統的部分EXCEL的操作也讓我做,順便結合之前操作EXCEL的經驗作一下總結,可能也算不上什么,對于絕大多數來說也沒什么技術含量,網上一搜一大把,但我想還是有必要總結一下,至少能給園子里的新手些許幫助,OK,Let's Go...
?? 一. 程序操作EXCEL的應用主要還是在統計報表方面,您可能會考慮讀EXCEL模板,也可能會考慮沒必要讀模板,其實讀不讀模板都能達到一樣的效果,看實際情況而用了。
???????1. 讀模板的話,首先模板存放在某個路徑下,根據模板把從數據庫里取出的數據寫回EXCEL然后生成一個新的EXCEL存放都另一個路徑以供下載,模板不變。
????????? 我這里的EXCEL操作主要是在VS2005里的,VS2003也可以的,不過沒怎么研究03里的操作(文章最后我會把05,03的示例下載地址貼上)vs05中操作EXCEL直接引用.NET自帶的COM組件,添加后項目的bin目錄下會自動出現
?????
Interop.Excel.dll這個DLL(需安裝office2003 excel,下面的說明及示例都是基于office2003的,版本不同調用可能會不一樣)
頁面的命名空間引用 using Excel;
下面是調用模板的一段代碼
?1??#region?使用模板導出Excel表
?2?????????????????case?"ReportByTemp":
?3?????????????????????{
?4?
?5?????????????????????????DataView?dv?=?Cache["ReportByTemp"]?as?DataView;
?6?????????????????????????//建立一個Excel.Application的新進程
?7?????????????????????????Excel.Application?app?=?new?Excel.Application();
?8?????????????????????????if?(app?==?null)
?9?????????????????????????{
10?????????????????????????????return;
11?????????????????????????}
12?????????????????????????app.Visible?=?false;
13?????????????????????????app.UserControl?=?true;
14?????????????????????????Workbooks?workbooks?=?app.Workbooks;
15?????????????????????????_Workbook?workbook?=?workbooks.Add(template_path?+?"\\EXCEL測試模板.xls");//這里的Add方法里的參數就是模板的路徑
16?????????????????????????Sheets?sheets?=?workbook.Worksheets;
17?????????????????????????_Worksheet?worksheet?=?(_Worksheet)sheets.get_Item(1);//模板只有一個sheet表
18?????????????????????????if?(worksheet?==?null)
19?????????????????????????{
20?????????????????????????????return;
21?????????????????????????}
22?
23?????????????????????????int?rowNum?=?0;
24?????????????????????????for?(int?i?=?0;?i?<?dv.Count;?i++)
25?????????????????????????{
26?????????????????????????????rowNum?=?i?+?1;
27?????????????????????????????worksheet.Cells[3?+?i,?1]?=?rowNum;
28?????????????????????????????worksheet.Cells[3?+?i,?2]?=?dv[i].Row[0].ToString();
29?????????????????????????????worksheet.Cells[3?+?i,?3]?=?dv[i].Row[1].ToString();
30?
31?????????????????????????????excelOperate.SetBold(worksheet,?worksheet.Cells[3?+?i,?1],?worksheet.Cells[3?+?i,?1]);?//黑體
32?????????????????????????????excelOperate.SetHAlignCenter(worksheet,?worksheet.Cells[3?+?i,?1],?worksheet.Cells[3?+?i,?3]);//居中
33?????????????????????????????worksheet.get_Range(worksheet.Cells[3?+?i,?1],?worksheet.Cells[3?+?i,?3]).Borders.Color?=?System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Black);
34?
35?????????????????????????}
36?
37?????????????????????????tick?=?DateTime.Now.Ticks.ToString();
38?????????????????????????save_path?=?temp_path?+?"\\"?+?tick?+?".xls";
39?????????????????????????workbook.SaveAs(save_path,?Missing.Value,?Missing.Value,?Missing.Value,?Missing.Value,?Missing.Value,?Excel.XlSaveAsAccessMode.xlNoChange,?Missing.Value,?Missing.Value,?Missing.Value,?Missing.Value,?Missing.Value);
40?????????????????????????excelOperate.Dispose(worksheet,?workbook,?app);//關閉Excel進程
41?
42?????????????????????}
43?????????????????????break;
44?????????????????#endregion 效果如下:
???????
???????2. 不讀模板的話,調用的時候其實會繼承一個空白模板,然后寫入數據,程序畫表頭,最終達到一樣的效果,程序如下:
?1??#region?不使用模板生成Excel表
?2?????????????????case?"ReportByNone":
?3?????????????????????{
?4?
?5?????????????????????????DataView?dv?=?Cache["ReportByNone"]?as?DataView;
?6?????????????????????????//建立一個Excel.Application的新進程
?7?????????????????????????Excel.Application?app?=?new?Excel.Application();
?8?????????????????????????if?(app?==?null)
?9?????????????????????????{
10?????????????????????????????return;
11?????????????????????????}
12?????????????????????????app.Visible?=?false;
13?????????????????????????app.UserControl?=?true;
14?????????????????????????Workbooks?workbooks?=?app.Workbooks;
15?????????????????????????_Workbook?workbook?=?workbooks.Add(XlWBATemplate.xlWBATWorksheet);//這里的Add方法里的參數就相當于繼承了一個空模板(暫這樣理解吧)
16?????????????????????????Sheets?sheets?=?workbook.Worksheets;
17?????????????????????????_Worksheet?worksheet?=?(_Worksheet)sheets.get_Item(1);
18?????????????????????????if?(worksheet?==?null)
19?????????????????????????{
20?????????????????????????????return;
21?????????????????????????}
22?
23?????????????????????????worksheet.get_Range(worksheet.Cells[1,?1],?worksheet.Cells[1,?3]).Merge(Missing.Value);?//橫向合并
24?????????????????????????worksheet.get_Range(worksheet.Cells[1,?1],?worksheet.Cells[1,?1]).Value2?=?"導出EXCEL測試一";
25?????????????????????????excelOperate.SetBold(worksheet,?worksheet.Cells[1,?1],?worksheet.Cells[1,?1]);?//黑體
26?????????????????????????excelOperate.SetHAlignCenter(worksheet,?worksheet.Cells[1,?1],?worksheet.Cells[1,?1]);//居中
27?????????????????????????excelOperate.SetBgColor(worksheet,?worksheet.Cells[1,?1],?worksheet.Cells[1,?1],?System.Drawing.Color.Red);//背景色
28?????????????????????????excelOperate.SetFontSize(worksheet,?worksheet.Cells[1,?1],?worksheet.Cells[1,?1],?16);//字體大小
29?????????????????????????excelOperate.SetRowHeight(worksheet,?worksheet.Cells[1,?1],?worksheet.Cells[1,?1],?32.25);//行高
30?????????????????????????worksheet.get_Range(worksheet.Cells[1,?1],?worksheet.Cells[1,?1]).Borders.Color?=?System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Black);//黑色連續邊框
31?
32?????????????????????????worksheet.Cells[2,?1]?=?"序號";
33?????????????????????????worksheet.Cells[2,?2]?=?"公司";
34?????????????????????????worksheet.Cells[2,?3]?=?"部門";
35?????????????????????????excelOperate.SetBold(worksheet,?worksheet.Cells[2,?1],?worksheet.Cells[2,?3]);?//黑體
36?????????????????????????worksheet.get_Range(worksheet.Cells[2,?1],?worksheet.Cells[2,?3]).Borders.Color?=?System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Black);
37?????????????????????????excelOperate.SetHAlignRight(worksheet,?worksheet.Cells[2,?1],?worksheet.Cells[2,?3]);
38?????????????????????????excelOperate.SetBgColor(worksheet,?worksheet.Cells[2,?1],?worksheet.Cells[2,?3],?System.Drawing.Color.Silver);//背景色
39?????????????????????????int?rowNum?=?0;
40?????????????????????????for?(int?i?=?0;?i?<?dv.Count;?i++)
41?????????????????????????{
42?????????????????????????????rowNum?=?i?+?1;
43?????????????????????????????worksheet.Cells[3?+?i,?1]?=?rowNum;
44?????????????????????????????worksheet.Cells[3?+?i,?2]?=?dv[i].Row[0].ToString();
45?????????????????????????????worksheet.Cells[3?+?i,?3]?=?dv[i].Row[1].ToString();
46?
47?????????????????????????????excelOperate.SetBold(worksheet,?worksheet.Cells[3?+?i,?1],?worksheet.Cells[3?+?i,?1]);?//黑體
48?????????????????????????????excelOperate.SetHAlignCenter(worksheet,?worksheet.Cells[3?+?i,?1],?worksheet.Cells[3?+?i,?3]);//居中
49?????????????????????????????worksheet.get_Range(worksheet.Cells[3?+?i,?1],?worksheet.Cells[3?+?i,?3]).Borders.Color?=?System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Black);//設置邊框顏色,不然打印預覽,會非常不雅觀
50?
51?????????????????????????}
52?????????????????????????excelOperate.SetColumnWidth(worksheet,?"A",?10);
53?????????????????????????excelOperate.SetColumnWidth(worksheet,?"B",?20);
54?????????????????????????excelOperate.SetColumnWidth(worksheet,?"C",?20);
55?????????????????????????worksheet.Name?=?"導出EXCEL測試一";
56?
57?????????????????????????tick?=?DateTime.Now.Ticks.ToString();
58?????????????????????????save_path?=?temp_path?+?"\\"+?tick?+?".xls";
59?????????????????????????workbook.SaveAs(save_path,?Missing.Value,?Missing.Value,?Missing.Value,?Missing.Value,?Missing.Value,?Excel.XlSaveAsAccessMode.xlNoChange,?Missing.Value,?Missing.Value,?Missing.Value,?Missing.Value,?Missing.Value);
60?????????????????????????excelOperate.Dispose(worksheet,?workbook,?app);//關閉Excel進程
61?
62?????????????????????}
63?????????????????????break;
64?
65?????????????????#endregion 效果如下:
以上我給了兩個最簡單的操作說明,下面詳細說一下對于一些稍微復雜的報表的生成處理
????? 二. 對于復雜的EXCEL報表的生成處理,無非是縱向合并相同的數據行及嵌套縱向合并等一些操作,下面就幾個具有針對性的報表作下說明.
??????????? 1.要生成相對復雜的EXCEL表,在從數據庫取數據時,要注意先按照合理的要求排好序,有時候可能order by后面要跟好幾個字段,而且這幾個字段誰先誰后也要注意,因為這些會直接影響報表呈現的效果,比如你的EXCEL表要按月份統計國內外的項目,顯示出來的時候要多個項目相同的人連續,那么排序就可能要這樣order by 月份,項目類別,用戶ID,項目ID(這是寫好的視圖,基于視圖來檢索的),這個排序的字段順序就不能變了,變了的話就不太好生成想要的形式了,如下圖:
這個也是動態畫的,用了個簡單的模板,模板就一個表頭,沒多大意義,除非表頭很復雜而且在列表中不需要重畫,考慮模板就比較好,向上面那個一月份國際的和其它月份的都是需要重畫表頭的。至于合并,如果不是嵌套的合并,我們可以在向模板循環寫數據的時候直接控制,比如下面一個簡單的寫法:
?1??for?(i?=?0;?i?<?table.Rows.Count;?i++)
?2?????????????????????????????{
?3?????????????????????????????????bidName?=?table.Rows[index]["BIDNAME"].ToString();
?4?????????????????????????????????if?(table.Rows[i]["BIDNAME"].ToString()?==?bidName)
?5?????????????????????????????????{
?6?????????????????????????????????????projNum++;
?7?????????????????????????????????????worksheet.Cells[5?+?i,?2]?=?table.Rows[i]["PROJNO"];
?8?????????????????????????????????????worksheet.Cells[5?+?i,?3]?=?table.Rows[i]["PROJNAME"];
?9?????????????????????????????????????worksheet.Cells[5?+?i,?4]?=?table.Rows[i]["STAT_DATE"];
10?????????????????????????????????????worksheet.Cells[5?+?i,?5]?=?table.Rows[i]["PROJTYPE"];
11?????????????????????????????????????worksheet.Cells[5?+?i,?6]?=?table.Rows[i]["CONTENT"];
12?????????????????????????????????????worksheet.Cells[5?+?i,?7]?=?table.Rows[i]["OPENDT"];
13?????????????????????????????????????worksheet.Cells[5?+?i,?8]?=?table.Rows[i]["OPENADDRESS"];
14?????????????????????????????????????worksheet.Cells[5?+?i,?9]?=?table.Rows[i]["REV_DATE"];
15?????????????????????????????????????worksheet.Cells[5?+?i,?10]?=?table.Rows[i]["BID_UNIT"];
16?????????????????????????????????????worksheet.Cells[5?+?i,?11]?=?table.Rows[i]["AGT_AMOUNT"];
17?????????????????????????????????????worksheet.Cells[5?+?i,?12]?=?table.Rows[i]["CURRENCY"]?+?":"?+?table.Rows[i]["BIDSER_AMOUNT"];
18?????????????????????????????????????worksheet.Cells[5?+?i,?13]?=?table.Rows[i]["SENDDATE"];
19?????????????????????????????????????worksheet.Cells[5?+?i,?14]?=?table.Rows[i]["CURRENCY"]?+?":"?+?table.Rows[i]["BIDPRICE"];
20?????????????????????????????????????worksheet.Cells[5?+?i,?15]?=?table.Rows[i]["BOOKAMOUNT"];
21?????????????????????????????????????worksheet.Cells[5?+?i,?16]?=?table.Rows[i]["CURRENCY"]?+?":"?+?table.Rows[i]["BAIL_AMOUNT"];
22?????????????????????????????????????worksheet.Cells[5?+?i,?17]?=?table.Rows[i]["USERNAME"];
23?????????????????????????????????????worksheet.Cells[5?+?i,?18]?=?table.Rows[i]["SECOND_USER"];
24?????????????????????????????????????worksheet.Cells[5?+?i,?19]?=?"";
25?????????????????????????????????????worksheet.get_Range(worksheet.Cells[5?+?i,?1],?worksheet.Cells[5?+?i,?19]).Borders.Color?=?System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Black);
26?????????????????????????????????????continue;
27?????????????????????????????????}
28?
29?????????????????????????????????worksheet.get_Range(worksheet.Cells[5?+?rowid,?1],?worksheet.Cells[5?+?i?-?1,?1]).Merge(Missing.Value);?//將第一列按投標單位合并
30?????????????????????????????????worksheet.get_Range(worksheet.Cells[5?+?rowid,?1],?worksheet.Cells[5?+?rowid,?1]).Value2?=?bidName?+?"("?+?projNum.ToString()?+?"個項目)";//合并后的單元格內容 合并單元格的時候也要注意一個問題,就是合并的單元格必須是為空的,不然在執行合并時,會提示“合并后的單元格的值將丟失”,具體不這樣提示的,大致是這個意思,一般我們合并都單元格相同的內容,在合并前我們先保存那個值,再清空后合并,上面的代碼中把worksheet.Cell[5+rowid,1]這里系列的單元格的值空出來了,沒寫數據,而且最后合并了再寫值,避免了去循環清空。
???? 2.嵌套的合并向上面那樣做可能控制比較麻煩,而且思路可能很混亂,我們可以考慮先循環填充所有的數據,在循環出來要合并的列,比如像下面的這張表
先循環填充數據,如下:
?1??int?index?=?0,?rownum?=?0;
?2?????????????????????????????string?ProjNo?=?"";
?3?????????????????????????????for?(i?=?0;?i?<?table.Rows.Count;?i++)
?4?????????????????????????????{
?5?????????????????????????????????ProjNo?=?table.Rows[index]["PROJNO"].ToString();
?6?????????????????????????????????if?(table.Rows[i]["PROJNO"].ToString()?==?ProjNo)
?7?????????????????????????????????{
?8?????????????????????????????????????wksheet.Cells[3?+?i,?1]?=?rownum?+?1;
?9?????????????????????????????????????wksheet.Cells[3?+?i,?2]?=?"'"?+?table.Rows[i]["PROJNO"];???//加上單引號保證以0開頭的字符原樣輸出
10?????????????????????????????????????wksheet.Cells[3?+?i,?3]?=?"'"?+?table.Rows[i]["PROJNAME"];
11?????????????????????????????????????wksheet.Cells[3?+?i,?4]?=?"'"?+?table.Rows[i]["PA_NAME"];
12?????????????????????????????????????wksheet.Cells[3?+?i,?5]?=?"'"?+?table.Rows[i]["BIDER_NAME"];
13?????????????????????????????????????wksheet.Cells[3?+?i,?6]?=?table.Rows[i]["BAIL_AMOUNT"];
14?????????????????????????????????????wksheet.Cells[3?+?i,?7]?=?table.Rows[i]["NOT_BACK"];
15?????????????????????????????????????wksheet.get_Range(wksheet.Cells[3?+?i,?1],?wksheet.Cells[3?+?i,?7]).Borders.Color?=?System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Black);
16?????????????????????????????????????continue;
17?????????????????????????????????}
18?
19?????????????????????????????????index?=?i;
20?????????????????????????????????rownum++;
21?????????????????????????????????i--;
22?
23?????????????????????????????} 下面合并前三列相同內容的單元:
?1??//合并前三列操作
?2?????????????????????????????int?m?=?1,?rowid?=?3,?k;
?3?????????????????????????????string?projName?=?"";
?4?????????????????????????????for?(k?=?3;?k?<=?i?+?2;?k++)
?5?????????????????????????????{
?6?????????????????????????????????if?(Convert.ToInt32(wksheet.get_Range(wksheet.Cells[k,?1],?wksheet.Cells[k,?1]).Value2)?==?m)
?7?????????????????????????????????{
?8?????????????????????????????????????ProjNo?=?wksheet.get_Range(wksheet.Cells[k,?2],?wksheet.Cells[k,?2]).Value2.ToString();
?9?????????????????????????????????????projName?=?wksheet.get_Range(wksheet.Cells[k,?3],?wksheet.Cells[k,?3]).Value2.ToString();
10?????????????????????????????????????wksheet.get_Range(wksheet.Cells[k,?1],?wksheet.Cells[k,?1]).Value2?=?"";
11?????????????????????????????????????wksheet.get_Range(wksheet.Cells[k,?2],?wksheet.Cells[k,?2]).Value2?=?"";
12?????????????????????????????????????wksheet.get_Range(wksheet.Cells[k,?3],?wksheet.Cells[k,?3]).Value2?=?"";
13?????????????????????????????????????continue;
14?????????????????????????????????}
15?????????????????????????????????wksheet.get_Range(wksheet.Cells[rowid,?1],?wksheet.Cells[k?-?1,?1]).Merge(Missing.Value);
16?????????????????????????????????wksheet.get_Range(wksheet.Cells[rowid,?1],?wksheet.Cells[rowid,?1]).Value2?=?m;
17?
18?????????????????????????????????wksheet.get_Range(wksheet.Cells[rowid,?2],?wksheet.Cells[k?-?1,?2]).Merge(Missing.Value);
19?????????????????????????????????wksheet.get_Range(wksheet.Cells[rowid,?2],?wksheet.Cells[rowid,?2]).Value2?=?"'"?+?ProjNo;
20?
21?????????????????????????????????wksheet.get_Range(wksheet.Cells[rowid,?3],?wksheet.Cells[k?-?1,?3]).Merge(Missing.Value);
22?????????????????????????????????wksheet.get_Range(wksheet.Cells[rowid,?3],?wksheet.Cells[rowid,?3]).Value2?=?"'"?+?projName;
23?
24?????????????????????????????????m++;
25?????????????????????????????????rowid?=?k;
26?????????????????????????????????k--;
27?????????????????????????????}
28?????????????????????????????//跳出循環后合并最后一個招標項目
29?
30?????????????????????????????wksheet.get_Range(wksheet.Cells[rowid,?1],?wksheet.Cells[k?-?1,?1]).Merge(Missing.Value);
31?????????????????????????????wksheet.get_Range(wksheet.Cells[rowid,?1],?wksheet.Cells[rowid,?1]).Value2?=?m;
32?
33?????????????????????????????wksheet.get_Range(wksheet.Cells[rowid,?2],?wksheet.Cells[k?-?1,?2]).Merge(Missing.Value);
34?????????????????????????????wksheet.get_Range(wksheet.Cells[rowid,?2],?wksheet.Cells[rowid,?2]).Value2?=?"'"?+?ProjNo;
35?
36?????????????????????????????wksheet.get_Range(wksheet.Cells[rowid,?3],?wksheet.Cells[k?-?1,?3]).Merge(Missing.Value);
37?????????????????????????????wksheet.get_Range(wksheet.Cells[rowid,?3],?wksheet.Cells[rowid,?3]).Value2?=?"'"?+?projName; 下面合并標段列
?1??//合并標段列
?2?
?3?????????????????????????????index?=?0;?rowid?=?3;?//重置變量
?4?????????????????????????????string?pa_name?=?string.Empty;?//標段名稱
?5?????????????????????????????for?(k?=?3;?k?<=?i?+?2;?k++)
?6?????????????????????????????{
?7?????????????????????????????????pa_name?=?table.Rows[index]["PA_NAME"].ToString();
?8?????????????????????????????????if?(wksheet.get_Range(wksheet.Cells[k,?4],?wksheet.Cells[k,?4]).Value2.ToString()?==?pa_name)
?9?????????????????????????????????{
10?????????????????????????????????????wksheet.get_Range(wksheet.Cells[k,?4],?wksheet.Cells[k,?4]).Value2?=?"";
11?????????????????????????????????????continue;
12?????????????????????????????????}
13?????????????????????????????????wksheet.get_Range(wksheet.Cells[rowid,?4],?wksheet.Cells[k?-?1,?4]).Merge(Missing.Value);
14?????????????????????????????????wksheet.get_Range(wksheet.Cells[rowid,?4],?wksheet.Cells[rowid,?4]).Value2?=?"'"?+?pa_name;
15?????????????????????????????????index?=?k?-?3;
16?????????????????????????????????rowid?=?k;
17?????????????????????????????????k--;
18?
19?????????????????????????????}
20?????????????????????????????//退出循環時合并最后一個項目的標段
21?????????????????????????????wksheet.get_Range(wksheet.Cells[rowid,?4],?wksheet.Cells[k?-?1,?4]).Merge(Missing.Value);
22?????????????????????????????wksheet.get_Range(wksheet.Cells[rowid,?4],?wksheet.Cells[rowid,?4]).Value2?=?"'"?+?pa_name;
23?????????????????????????????tick?=?DateTime.Now.ToString("yyyyMMddhhmmss");
24?????????????????????????????save_path?=?temp_path?+?"\\"?+?tick?+?"保證金收退情況表.xls";
25?????????????????????????????Session["BailBackID"]?=?tick?+?"保證金收退情況表.xls";
26?????????????????????????????Session["_BailBack"]?=?"true";
27?????????????????????????????workbook.SaveAs(save_path,?Missing.Value,?Missing.Value,?Missing.Value,?Missing.Value,?Missing.Value,?Excel.XlSaveAsAccessMode.xlNoChange,?Missing.Value,?Missing.Value,?Missing.Value,?Missing.Value,?Missing.Value);
28?????????????????????????????excelOperate.Dispose(worksheet,?workbook,?app);//關閉Excel進程
29?????????????????????????????//DownLoad(save_path);
30?????????????????????????????//Page_Close(); 當然,上面的操作中會進行好幾次循環,在性能方面不太可取,園子里的兄弟也許會有更好的方法,小弟不吝賜教了
下面我們看下幾個效果圖:
(注意:這里提示的導出數據是指從數據庫成功取出數據,還沒有操作EXCEL對象,剛開始已經說過了,當然這個提示文字換成其它的也可以)
整個過程采用AJAX提示的,一來不刷新,二來導出時間比較長的話,可以給客戶一個良好的體驗效果,否可,用戶一點導出按鈕,半天沒反應也沒提示,客戶就覺得怎么這么慢的,是不是你們程序有問題,指責一大堆,有了這么些交互提示信息,讓客戶多等幾分鐘也能承受。
???? 3.生成的表格包含多個sheet的操作,比如下面一種情況
繪制這張表的要求是根據選擇某年的幾月到幾月,生成這個幾個月的一個綜合情況的sheet,然后分別生成這幾個月的單獨的sheet表,生成上面表的模板,包含兩個sheet ,一個綜合月份的sheet和一個單獨月份的sheet,因為單獨月份的sheet表現形式都是一樣的,我們可以根據選擇的月份個數Copy幾個sheet就可以了
?1??Workbooks?workbooks?=?app.Workbooks;
?2?
?3?????????????????????????????_Workbook?workbook?=?workbooks.Add(template_path?+?"\\招標單位年度招標情況逐月統計表.xls");
?4?????????????????????????????Sheets?sheets?=?workbook.Worksheets;
?5?????????????????????????????_Worksheet?Yearsheet?=?(_Worksheet)sheets.get_Item(1);
?6?????????????????????????????_Worksheet?worksheet?=?(_Worksheet)sheets.get_Item(2);
?7?????????????????????????????if?(worksheet?==?null)
?8?????????????????????????????{
?9?????????????????????????????????return;
10?????????????????????????????}
11?????????????????????????????for?(int?i?=?1;?i?<?monthCount;?i++)
12?????????????????????????????????worksheet.Copy(Missing.Value,?workbook.Worksheets[2]);//月統計工作薄
Yearsheet的操作就不說了,和前面幾個一樣操作,關鍵是月份的sheet的生成,其實就是循環操作get_Item(i),代碼如下
?1??//每月詳細統計
?2?
?3?????????????????????????????int?item_id?=?2;
?4?????????????????????????????rowNum?=?0;?book_Amount?=?0;?index?=?0;
?5?????????????????????????????bid_Amount?=?"";?bidser_Amount?=?"";?agent_Amount?=?0;//清空變量
?6?????????????????????????????_Worksheet?ws?=?null;
?7?????????????????????????????for?(int?i?=?0;?i?<?tableMM.Rows.Count;?i++)
?8?????????????????????????????{
?9?????????????????????????????????rowNum++;
10?????????????????????????????????Month?=?tableMM.Rows[index]["DATE_MONTH"].ToString();
11?????????????????????????????????if?(tableMM.Rows[i]["DATE_MONTH"].ToString()?==?Month)
12?????????????????????????????????{
13?????????????????????????????????????ws?=?(_Worksheet)sheets.get_Item(item_id);
14?????????????????????????????????????ws.Cells[3?+?rowNum?-?1,?1]?=?rowNum;
15?????????????????????????????????????ws.Cells[3?+?rowNum?-?1,?2]?=?tableMM.Rows[i]["PROJNO"];
16?????????????????????????????????????ws.Cells[3?+?rowNum?-?1,?3]?=?tableMM.Rows[i]["PROJNAME"];
17?????????????????????????????????????ws.Cells[3?+?rowNum?-?1,?4]?=?tableMM.Rows[i]["BID_TYPE"];
18?????????????????????????????????????ws.Cells[3?+?rowNum?-?1,?5]?=?tableMM.Rows[i]["BID_MODE"];
19?????????????????????????????????????ws.Cells[3?+?rowNum?-?1,?6]?=?tableMM.Rows[i]["OPENDT"];
20?????????????????????????????????????ws.Cells[3?+?rowNum?-?1,?7]?=?tableMM.Rows[i]["OPENADDRESS"];
21?????????????????????????????????????ws.Cells[3?+?rowNum?-?1,?8]?=?tableMM.Rows[i]["BID_UNIT"];
22?????????????????????????????????????ws.Cells[3?+?rowNum?-?1,?9]?=?tableMM.Rows[i]["NOTICE_NO"].ToString().Replace("神華國貿",?"");
23?????????????????????????????????????ws.Cells[3?+?rowNum?-?1,?10]?=?tableMM.Rows[i]["BOOKAMOUNT"];
24?????????????????????????????????????ws.Cells[3?+?rowNum?-?1,?11]?=?tableMM.Rows[i]["BIDPRICE"]?+?"(萬"?+?tableMM.Rows[i]["CURRENCY"]?+?")";
25?????????????????????????????????????ws.Cells[3?+?rowNum?-?1,?12]?=?tableMM.Rows[i]["BIDSER_AMOUNT"]?+?"(萬"?+?tableMM.Rows[i]["CURRENCY"]+")";
26?????????????????????????????????????ws.Cells[3?+?rowNum?-?1,?13]?=?tableMM.Rows[i]["AGT_AMOUNT"];
27?????????????????????????????????????ws.Cells[3?+?rowNum?-?1,?14]?=?"";
28?????????????????????????????????????ws.get_Range(ws.Cells[3?+?rowNum?-?1,?1],?ws.Cells[3?+?rowNum?-?1,?14]).Borders.Color?=?System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Black);
29?????????????????????????????????????continue;
30?????????????????????????????????}
31?
32?????????????????????????????????ws.Cells[1,?1]?=?year?+?"年"?+?bidName?+?GetMonth(Month)?+?"月份招標項目情況一覽表";
33?
34?????????????????????????????????//每月合計
35?????????????????????????????????sql?=?"?SELECT?CURRENCY,?NVL(SUM(BIDPRICE),0)?AS?BIDPRICE,NVL(SUM(BOOKAMOUNT),0)?AS?BOOKAMOUNT,NVL(SUM(BIDSER_AMOUNT),0)?AS?BIDSER_AMOUNT,NVL(SUM(AGT_AMOUNT),0)?AS?AGT_AMOUNT?FROM?IBS_V_BID_MONTHLY_STAT"?+?SqlFilter?+
36????????????????????????????????????????????"?AND?DATE_YEAR?='"?+?year?+?"'?AND?COMPANY_ID="?+?biderID?+?"?AND?DATE_MONTH?='"?+?Month?+?"'"?+
37????????????????????????????????????????????"?GROUP?BY?CURRENCY";
38?????????????????????????????????System.Data.DataTable?dt1?=?OracleHelper.RetDataTable(sql);
39?????????????????????????????????for?(int?m?=?0;?m?<?dt1.Rows.Count;?m++)
40?????????????????????????????????{
41?????????????????????????????????????bid_Amount?+=?dt1.Rows[m]["BIDPRICE"]?+?"(萬"+dt1.Rows[m]["CURRENCY"]?+?")\r\t";
42?????????????????????????????????????book_Amount?+=?float.Parse(dt1.Rows[m]["BOOKAMOUNT"].ToString());
43?????????????????????????????????????bidser_Amount?+=?dt1.Rows[m]["BIDSER_AMOUNT"]?+?"(萬"?+?dt1.Rows[m]["CURRENCY"]?+?")\r\t";
44?????????????????????????????????????agent_Amount?+=?float.Parse(dt1.Rows[m]["AGT_AMOUNT"].ToString());
45?????????????????????????????????}
46?
47?????????????????????????????????ws.Cells[3?+?rowNum?-?1,?3]?=?"合??計";
48?????????????????????????????????ws.Cells[3?+?rowNum?-?1,?10]?=?book_Amount;
49?????????????????????????????????ws.Cells[3?+?rowNum?-?1,?11]?=?bid_Amount;
50?????????????????????????????????ws.Cells[3?+?rowNum?-?1,?12]?=?bidser_Amount;
51?????????????????????????????????ws.Cells[3?+?rowNum?-?1,?13]?=?agent_Amount;
52?????????????????????????????????ws.get_Range(ws.Cells[3?+?rowNum?-?1,?1],?ws.Cells[3?+?rowNum?-?1,?14]).Borders.Color?=?System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Black);
53?????????????????????????????????ws.Name?=?GetMM(Month);
54?
55?????????????????????????????????item_id++;
56?????????????????????????????????index?=?i;?//匯總下一個月份的招標項目
57?????????????????????????????????i--;
58?????????????????????????????????rowNum?=?0;?book_Amount?=?0;
59?????????????????????????????????bid_Amount?=?"";?bidser_Amount?=?"";?agent_Amount?=?0;//清空變量
60?????????????????????????????}
61?
62?????????????????????????????//跳出循環時進行最后一個月份的項目匯總
用的是oracle數據庫,所以上面那個sql語句。。。 呵呵
============================================================================================
上面大致說得就差不多了,因為是不斷循環的什么的,可能對于大的數據量讀寫來說,比較好性能,如果大家有什么更好的方法,可以指點下,為了彌補等待時間過長,所以才結合了AJAX來處理。
最后我把做的一個小demo的鏈接帖出來給大家,還有一些空模板和對應生成的數據表給大家對照看下,尤其相對復雜一些的表畫應該是能畫出來的,主要看大家采用什么樣的方法,能少循環一次就盡量少循環,呵呵~~~
?? http://www.justlike.com.cn/upfiles/template_xls.rar
?? http://www.justlike.com.cn/upfiles/ExcelFiles.rar
?? http://www.justlike.com.cn/upfiles/ExcelReportDemo.rar
(說明:最后彈出下載文件的一個頁面一直想讓其自動關掉,但是不行,如果不關掉,再點導出,不會彈出下載框,實際的處理中我們可以在導出旁邊放個下載按鈕,就像上面的效果圖里那樣,當然可以點導出的時候讓其在網頁中直接打開,點下載的時候再彈出下載框,但是直接打開的話,文件需要生成在虛擬目錄下,不太安全,呵呵~~,看實際情況處理了)
==========================================================================================
今天補充說明下,關于那個調用ajax回調的效果,有個地方用到了所謂的“ajax嵌套調用”,如下
?2??{
?3???????if(resp.value?==?"OK")
?4???????{
?5????????????
?6??????????????$('tipMsg').innerHTML?=?"<img?border=\"0\"?src=\"images/s_progressbar.gif\"><font?color=#FF0000?style=font-weight:bold>準備導出數據,請稍等</font>";
?7??????????????setTimeout("RedirectUrl()",1000);//延時體驗??
?8???????}
?9???????else
10????????if(resp.value?==?"NO")
11????????{
12???????????$('tipMsg').innerHTML?=?"<font?color=#FF0000?style=font-weight:bold>沒有找到符合該查詢條件的數據</font>";
13???????????$('btnExcel').disabled?=?false;
14????????}
15???????else
16???????{
17???????????$('tipMsg').innerHTML?=?"<font?color=#FF0000?style=font-weight:bold>警告:導出數據出錯</font>";
18???????????$('btnExcel').disabled?=?false;
19???????}
20????????
21???????
22??}
?
?1?function?RedirectUrl()?2??{
?3??????$('tipMsg').innerHTML?=?"<img?border=\"0\"?src=\"images/ajaxloading.gif\"><font?color=#7fffd4?style=font-weight:bold>正在讀寫報表文件,請稍后</font>";
?4?????????var?ajax?=?new?ajax_request("ExcelReport.aspx?flag=ReportByTemp&"+Math.random(),?"",?"",?ReportCallback);?
?5?????????function?ReportCallback(resp)
?6?????????{
?7?????????????if(resp.value?!=?"Error"?&&?resp.value?!="")
?8?????????????{
?9????????????????$('btnExcel').disabled?=?false;
10????????????????$('tipMsg').innerHTML?=?"<font?color=#FF0000?style=font-weight:bold>數據導出成功!</font>";
11????????????????Open("XLS_DownLoad.aspx?path="+resp.value);//window.location.href?=?resp.value;//
12?????????????}
13?????????????else
14?????????????{
15????????????????$('btnExcel').disabled?=?false;
16????????????????$('tipMsg').innerHTML?=?"<font?color=#FF0000?style=font-weight:bold>文件讀寫出錯,請檢查文件模板是否存在或對文件是否有讀寫權限!</font>";
17?????????????}
18?????????}
19?
20??}
21??
22??function?Open(url)?
23?{
24?????window.open(url,'newwindow','height=1,width=1,top=1500,left=1500,toolbar=no,menubar=no,scrollbars=yes,location=no,status=no')
25?}
ExcelReportCallback(resp)原本是一個回調函數,但是里面調用了一個RedirectUrl()方法,這個方法又包含了一個回調函數,這樣就形成了回調的嵌套,之所以這么做,是因為,第一個回調是處理從數據庫取出數據成功與否,如果成功了跳轉到畫EXCEL的頁面,這樣的話會出現一個空白頁等生成好后出現下載框,后來覺得是否可以嵌套一個回調來繼續一次異步操作,這樣就不會出現長時間等待的空白頁面了,而是生成好EXCEL后返回地址,或者可以返回一個文件名到XLS_DownLoad.aspx頁面直接下載,但是XLS_DownLoad.aspx也是要出現的,我嘗試過讓下載后這個頁面自動關閉,無賴做不到,所以把Open()方法里的數據值調得讓頁面不顯示,但是狀態欄還是有顯示的。
到這里算是寫完了,決定奢侈下,放到首頁下:),總覺得首頁的文章只有高手才能放,而且放到首頁也是一種奢侈,希望對園子里的某些人有一定的幫助吧~~
轉載于:https://www.cnblogs.com/gllgsoft/archive/2008/11/24/1339884.html
總結
以上是生活随笔為你收集整理的告别ASP.NET操作EXCEL的烦恼的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 爱情麻辣烫防骗子—骗子谎称学生出事让家长
- 下一篇: [转] 关于ASP.NET中由于无法创建