利用 ASP.NET 建立多頁自訂報表
發布日期 : 4/1/2004 | 更新日期 : 4/1/2004
Chandra Kamalakantha
EDS Corporation
Marius Rochon
Microsoft Corporation
2002 年 9 月
適用於:
Microsoft ASP.NET
Microsoft Visual Studio .NET
摘要:講述一種利用現有的 ASP.NET 基礎結構(設計器、資料繫結和其他運行時功能)來產生簡單的和複雜的多頁 HTML 報告的方法。 (7 頁列印頁)
下載 Reporttool.exe。
本頁內容
簡介
我們的方法
利用資料繫結建立報表
運行時
小結
致謝
關於作者
簡介
本文講述一種利用現有的 ASP.NET 基礎結構 — 設計器、資料繫結和其他運行時功能 — 來產生簡單的和複雜的報表的方法。 報表由包含多頁資料的 HTML 構成。 在通常情況下,Microsoft ASP.NET 用於處理單頁的表單,其中帶有一組 UI 控制項。 出於進行報告的目的,我們需要讓 ASP.NET 產生相同 HTML 輸出的重複序列,直到用盡所有報表資料為止。 為了達到這一目的,我們擴充了 System.Web.UI.Page類的功能。 具體來講,我們重寫了 Render 方法並增加了另外一些其他設計時屬性。 利用這個新類,開發人員可以使用標準的 Microsoft Visual Studio .NET 表單設計器來設定報表頁面的布局,設定其屬性以及所包含的各個控制項的屬性,並執行該項目以便產生綁定到傳入資料的各個連續組成部分的、具有相同布局的一個 HTTP 響應流。
此報表所產生的一個輸出樣本包含於 Report.htm 檔案中。
我們擴充了該新類的功能以便允許多個輸入資料流,在同一報表中使用多個可選的頁面配置(例如,第一頁,報表總計頁,明細頁,等等),並能夠逐頁瀏覽整個報表(而不用反覆訪問伺服器)。 所有相關的代碼都包含在 ReportClass 項目中。 MSDNArticleTest 項目中包含了利用此架構的樣本報表定義。
返回頁首 我們的方法
ASP.NET 以立即可用的方式支援一次一頁 (HTML Form) 的呈現方式。 因此,可以使用它根據使用者對報表的每個頁面的請求而作出響應,從而呈現該頁面。 然而,這需要使用者幹預才能產生整個報表,並且需要在對伺服器的不同訪問之間保持遊標狀態,如果要整體產生該報表,則這可能是一種比較昂貴的需要。
然而,ASP.NET 還提供了設計和運行時可擴充架構,這就使得我們可以更改其預設行為。 在此方法中,我們已經使用了一個新類 (ReportPage) 來重寫 System.Web.UI.Page 類(預設情況下,ASP.NET 表單是從此類派生出來的)的預設表單處理方式。
Report 類的基本操作體現在其 Render 方法中,該方法重寫(並替換)了 System.Web.UI.Page 中的 Render 方法:
首先,跳過與 Form 標記相關的 HTML 產生過程 — 這是不必要的,並且實際上會干擾其他控制項 ID 的重複使用。載入一個以足夠資料填充報表頁的資料集(利用 DataGrid 的頁面大小)。 接下來,調用 DataBind以便將資料與頁面上的所有控制項進行關聯。 利用各個控制項的標準 Render 方法對其進行呈現;首先載入資料集,重複此操作直到沒有要載入的資料為止。 最後,調用結束標記的 Render 方法。
返回頁首 利用資料繫結建立報表
我們將要建立的樣本報表(如下所述)將提供該報表的下列特性:
利用資料繫結建立報表
1.建立一個新的解決方案,將其命名為 "CustomReporting"。
2.建立一個類庫類型的新 C# 項目,將其命名為 "ReportClass"。
3.刪除 Class1.cs 模組。
4.將所附帶的 ReportPage.cs 模組下載到電腦。
5.單擊該 ReportClass 項目,單擊 Add Existing Item,然後將 ReportPage.cs 添加到該 ReportClass 項目。
6.在 ReportClass 項目中添加對 System.Data 和 System.Web 的引用。
7.產生類庫以準備好利用資料繫結來建立報表。
8.向 CustomReporting 解決方案中添加一個新的 ASP.NET Web 項目,並將其命名為 "ReportWriterTest"。
9.在 ReportWriterTest 下添加一個到 ReportClass 的引用。 (單擊 References,在 Projects 選項卡上,選擇 ReportClass 項目。) 包含 ReportClass.dll(顯示於 Selected components 部分)。
10.通過添加 Reportclass,編輯 WebForm1.aspx。
11.將
public class WebForm1 : System.Web.UI.Page
更改為
public class TestReport : ReportClass.ReportPage
這樣就會強制 Web 頁面從 ReportClass.ReportPage 進行繼承,這樣一來測試 Web 頁面就能夠利用 ReportPage類(ReportClass 類庫的一部分)所公開的屬性和方法了。
12.產生 ReportWriterTest 項目。
13.在設計器中編輯 WebForm1.aspx,並設計報表布局。 在本樣本中,我們將根據 authors 表(Microsoft SQL Server? 中所駐留的 pubs 資料庫的一部分)產生報表。
編輯 WebForm1.aspx 並設計報表布局
a.添加一個包括兩行四列的 HTML 表格。
b.編輯 HTML 並刪除該表格的 style 屬性。
c.將 cellSpacing、cellPadding 和 border 設定為 0。
在該表格的第一行中,添加兩個標籤控制項。 第一個標籤用於 Page 標記,而第二個標籤將顯示頁號;因此它將被命名為 "lblPage" 而文本應被設定為空白格。
e.在該表格的第二行中,添加兩個標籤控制項。 第一個標籤控制項將被用於標籤標記狀態。 第二個標籤控制項將被命名為 "lblState",其文本將被設定為 empty spaces。
f.在第三行上,刪除四列中的三列,僅剩餘一列。 將該列的寬度設定為與表格寬度相同。
g.在 HTML 表格中,把一個資料繫結網格控制項拖到第三行。
h.編輯該資料繫結網格列集合,並設定四列;分別用於作者的姓、名、地址和城市。 利用 Bound Column 並根據郵遞區號統計頁面總數。 請注意: 在運行時,請取消選中 Create columns automatically。
i.在第四行上,添加另兩個標籤。 第一個標籤的文本將被設定為 total,而第二個標籤的文本被設定為 empty spaces且將被命名為 "lblTotal"。
j.將整個表格嵌入一個面板中,並給該面板指定 ID 為 Page1。 確保該面板被設定為在伺服器上運行。
k.將一個非類型化資料集拖到表單上。
l.導航至 Properties 選項卡並選擇 WebForm1.aspx 頁。 將 dataset屬性設定為該頁面上的資料集。 將 data-bound 網格設定為頁面上的資料繫結網格。
m.在該 Web 頁面的 Page_Load 事件中填充該資料集。
n.包含以下代碼,以便填充資料集:
private void Page_Load(object sender, System.EventArgs e) { if ( IsPostBack) return; string sConnectionString = "Provider=SQLOLEDB;data source=.; initial catalog=pubs; User ID=sa; Password=****"; string sSQL = "select au_lname, au_fname, address, city, state, zip from authors order by state"; OleDbConnection dbCon = new OleDbConnection(sConnectionString); OleDbCommand dbCmd; OleDbDataAdapter dbAdapt = new OleDbDataAdapter(); try { dbCon.Open(); dbCmd = new OleDbCommand(sSQL, dbCon); dbAdapt.SelectCommand = dbCmd; dbAdapt.Fill(dataSet1); dbAdapt.Dispose(); dbCmd.Dispose(); } catch (Exception e1) { Response.Write("Database error " + e1.Message); } finally { dbCon.Close(); dbCon.Dispose(); } }
14.根據列設定頁面組/組分隔字元:
base.TrackColumnBreaks("one", "state"); This will provide an override function and exposes the row that accounted for column/page break. protected override void ProcessPageBreak() { lblState.Text = CurrentDataRow["state"].ToString(); }
15.設定並跟蹤總數:
base.TrackTotals("zip",ReportClass.TotalsScopeEnum.Page); base.TrackTotals("zip",ReportClass.TotalsScopeEnum.Report);
16.其他可重寫的函數包括:ProcessPageBreak、PostProcessPageBreak、ProcessGroupBreak、PostProcessGroupBreak、ProcessReportEnd和 ProcessCurrentRow。 建議不要重寫 ProcessCurrentRow。 開發人員可根據具體情況來重寫這些函數以重設或列印內容。
17.要在報表中添加導航條,請將 Pagenav.js 包含到項目中,並將其包括到每個報表頁上。 將 ViewReport.aspx、Reportdetail.htm 和 Reportheader.htm 包括到該項目中。 ShowReport.aspx 中包含一個樣本,用以說明如何調用 Viewreport.aspx 進行頁面導航。 這種導航功能所完成的唯一動作就是在各個連結(例如,http://localhost/MSDNTest/WebForm1.aspx#Page[1-n])之間移動。
返回頁首 運行時
當您執行此報表時,會發生什麼情況? Report 類的實際操作都在其 Render 方法中,該方法重寫了標準 Page 類中的同一方法。
開始 HTML 標籤是通過調用 Controls[0].render 方法而呈現的。 在某個階段,Control.Render將調用 Page.VerifyRenderingInServerForm。 此函數的預設實現方法將引發一個異常;因此,在 Report 類中重寫此函數是為了不進行任何操作。
ReportClass 迴圈處理資料集 tables[0] 以便建立一個多頁報表。 調用 LoadPage方法以便將足夠資料載入(首先清除)到 DataSet 中,從而產生下一頁報表。 LoadPage方法是可重寫的,因此您可以在此處提供自己的邏輯。 此外,LoadPage 方法會調用虛擬函數 OnNextRow,您可以重寫此虛擬函數以便進行一些特殊的處理,例如,檢測資料分隔,計算小計(您可以將其儲存在資料集的一個表中)等等。如果您確實要重寫這些方法,並想要強制進行分頁,則應將 Report.m_PageFull 設為 True。 要完全停止進一步的輸出,請將 MoreData 設為 True。 LoadPage 會調用 DataBind 方法。
Page.Render 方法插入 Html 以便強制進行分頁。 調用 AllControls.RenderControls方法以便強制呈現頁面上的各個控制項。 重複進行以上步驟,直到所指定的資料集中資料行耗盡為止。 結束 HTML 標籤 (Controls[2].RenderControl) 被調用,資料庫連接被關閉,Render 完成。
返回頁首 小結
本樣本說明了如何能夠利用相對很少的幾行代碼將 ASP.NET 的基本範例從呈現 HTML 表單更改為產生多頁報表。 現有 ASP.NET 基礎結構的絕大部分都原封未動 — 所有的工具箱控制項都是可用的,可通過屬性視窗設定這些控制項的呈現屬性,且真正的呈現過程仍然由現有代碼執行。 然而,所產生的輸出卻可用作一個明顯不同的用途。
返回頁首 致謝
在此,我們想感謝以下人士:
Microsoft 諮詢服務部門的 David Powell 和 Scott Beaudreau 協助我們開始使用 .NET 並指導小組完成了本項目的初始階段
Mark Wadsworth、Frank Degise 和 Linda Sutton 不斷提供支援和鼓勵,才使我們得以出版這篇文章。
Tushar Patwardhan 和 Neeraj Pathania 協助測試和修複了所有問題,我們還要感謝 Chandra 在 EDS Corporation 的小組同事。
返回頁首