簡介

其實我對報表程式沒有太大的興趣,只是有時候工作上碰到了,還是得實際動手做做看,以大致了解這東西的架構與開發方式。這篇文章就是在練習之餘,順手整理的筆記(說是順手,可是剪一堆圖還真是有點麻煩)。

這裡的入門範例程式非常簡單,可以說簡單到幾乎沒有實用的價值,不過應該足以了解報表程式開發的流程,並且認識 pull mode 與 push model 兩種報表運作模式的差異。另外要說明的是,這裡的報表範例並非採用報表伺服器的架構,而是在應用程式伺服器上面直接產生 Web 報表。

軟體需求:

  • Visyal Studio 2005
  • Crystal Reports XI Developer Edition Release 2

請注意,CR XI 的 R2 版才有支援 Visual Studio 2005,你可以至 Crystal Reports 官方網站下載 R2 版

以下分別依報表設計、撰寫程式,以及部署等三項工作說明開發的步驟,最後則是將此範例程式稍微變化一下,讓它比較接近實際開發時所採用的作法。

Part I. 設計報表

  1. 開啟 Crystal Reports XI。
  2. 從主選單點選「檔案 > 新增 > 標準報表」。
  3. 接著要建立資料連線。在「可用的資料來源」面板中展開「建立新連接」項目,根據你想要連接的資料庫類型選擇適當的連線項目,這裡示範連接 SQL Server 資料庫,因此選擇 OLEDB (ADO),如圖1所示。
  4. 接著會開啟資料庫連線設定視窗,選擇「SQL Native Client」,然後按「下一步」,如圖2
  5. 輸入連線參數,然後按「完成」鈕,見圖3
  6. 回到「資料庫專家」視窗後,展開剛剛新增的資料庫連線項目,雙擊「加入命令」或依圖4操作。
  7. 接著輸入 SQL 命令 "select * from Customers",如圖5。輸入完畢後,連按兩次「確定」鈕結束關閉所有對話窗,便會回到報表設計畫面。
  8. 在報表設計畫面中,可以看到有一個名為「報表1」的頁籤,底下有「設計」和「預覽」兩個子頁籤。先切到「設計」頁籤,然後從右邊的「欄位總管」視窗中的「資料庫欄位 > 命令」底下拖幾個欄位到設計頁面的「細目」區塊。參考圖6
  9. 接著切到「預覽」視窗,就能看到預覽的結果,如圖7所示。
  10. 從主選單點選「檔案 > 報表選項」,將「儲存報表的資料」(Saved Data)選項取消勾選。注意此步驟一定要做,否則以後每次檢視報表時,都只會抓取儲存於報表檔內的靜態資料,而不會向資料庫查詢。參考圖8。(註:如果你希望每次新建立的報表都不要儲存靜態資料,可以至「檔案 > 選項 > 報表頁籤」將「儲存報表的資料」項目取消勾選)
  11. 從主選單點選「檔案 > 儲存」,將檔案命名為 "Customers.rpt",並儲存在你的 Web 應用程式的目錄下(如果你還沒建立,此時可以先將 Web 應用程式的目錄建立好,稍後就會說明應用程式的撰寫)。
  12. 關閉 Crystal Reports 設計視窗。

註:VS2005 本來就有內建 Crystal Reports,而且安裝了 Crystal Reports XI R2 之後,VS2005 的內建報表元件也會升級成 R2 版,因此你也可以直接在 VS2005 裡面完成上述報表設計的工作。作法是從 Toolbox 的 Crystal Reports 頁籤中拖一個 CrystalReportSource 控制項到網頁上,然後點控制項右上角的智慧標籤,接著在智慧標籤選單中點選「設定 Report Source」,再於開啟的對話窗中選擇「新增報表」。

Part II. 撰寫 Web 程式

  1. 開啟 Visual Studio 2005,New 一個 Web 應用程式專案。
  2. New 一個新網頁,檔案名稱取名為 SampleRpt1.aspx。
  3. 從 Toolbox 的 Crystal Reports 頁籤中拉一個 CrystalReportViewer 控制項到 SampleRpt1.aspx 頁面上,然後點一下控制項右上角的智慧標籤,將一些不需要的功能取消,參考圖9。建議您此時看一下網頁原始碼有何變化(加入了哪些標籤)。
  4. 從 Toolbox 的 Crystal Reports 頁籤中拉一個 CrystalReportSource 控制項到SampleRpt1.aspx 頁面上,接著在屬性視窗中展開 Report 屬性,設定 FileName 為 "Customers.rpt"(這個報表檔案必須跟網頁放在同一個目錄下)。注意裡面還有一個 DataSources 屬性,這表示你還可以額外指定報表的資料來源(此範例不指定任何 DataSources),相關說明請參考 MSDN 網站上的文章〈將 CrystalReportSource 連接到 SqlDataSource 控制項〉,網址為:http://msdn2.microsoft.com/zh-tw/library/ms227842(VS.80).aspx
  5. 設定 CrystalReportSrouce1 控制項的 ReportSourceID 屬性為 CrystalReportSource1,然後你就會看到頁面上的報表資料已經全部帶出來,參考圖10
  6. 在瀏覽器中檢視 SampleRpt1.aspx(在 Solution Explorer 中的 SampleRpt1.aspx 上面點右鍵,選擇 View in Browser)。執行結果如圖11

你會發現報表的右上角有 "BusinessObjects" 標誌,而且中間的「主報表」下拉清單在這裡也是多餘的,若要拿掉這些物件,可以將 CrystalReportViewer 控制項的 HasCrystalLogo 和 HasViewList 屬性設為 False。

Part III. 部署報表

由於此報表範例並非採用報表伺服器的架構,而是直接在應用程式伺服器上面產生報表,因此在部署報表時,必須在應用程式伺服器上面安裝 Crystal Reports XI Developer Edition Release 2(end user 端完全不用安裝任何元件)。你可以直接在機器上安裝 CR XI R2,或者利用 Visual Studio 2005 建立安裝專案,相關的部署選項可參考官方文件的說明,或者這篇舊文可能也有些用處:部署 Crystal Reports 共用元件

網站的 web.config 中要加入組件參考:

<add assembly="CrystalDecisions.CrystalReports.Engine, Version=11.5.3700.0, Culture=neutral, PublicKeyToken=692FBEA5521E1304"/>
<add assembly="CrystalDecisions.Shared, Version=11.5.3700.0, Culture=neutral, PublicKeyToken=692FBEA5521E1304"/>
<add assembly="CrystalDecisions.Web, Version=11.5.3700.0, Culture=neutral, PublicKeyToken=692FBEA5521E1304"/>
<add assembly="CrystalDecisions.ReportSource, Version=11.5.3700.0, Culture=neutral, PublicKeyToken=692FBEA5521E1304"/>
<add assembly="CrystalDecisions.Enterprise.Framework, Version=11.5.3300.0, Culture=neutral, PublicKeyToken=692FBEA5521E1304"/>
<add assembly="CrystalDecisions.Enterprise.Desktop.Report, Version=11.5.3300.0, Culture=neutral, PublicKeyToken=692FBEA5521E1304"/>
<add assembly="CrystalDecisions.ReportAppServer.Controllers, Version=11.5.3300.0, Culture=neutral, PublicKeyToken=692FBEA5521E1304"/>
<add assembly="CrystalDecisions.Enterprise.InfoStore, Version=11.5.3300.0, Culture=neutral, PublicKeyToken=692FBEA5521E1304"/>
<add assembly="CrystalDecisions.Enterprise.Viewing.ReportSource, Version=11.5.3300.0, Culture=neutral, PublicKeyToken=692FBEA5521E1304"/>

部署完成後,應用程式伺服器的預設網站底下應該會有個名為 "crystalreportviewer115" 的虛擬目錄,且預設網站的根目錄(預設為 C:\Inetpub\wwwroot)底下會有資料夾:aspnet_client\system_web\2_0_50727\ crystalreportviewers115。如果沒有,你可以從開發機器將該目錄的檔案複製到應用程式伺服器上。若少了這些檔案,當使用者在網頁上 預覽報表時,工具列上的按鈕圖片就會看不到,一些 JavaScript 功能也會失效。

2008-1-31 增補:

如果你發現在用戶端瀏覽器中預覽報表時,預覽視窗有開啟,工具列按鈕也正常,可是按預覽視窗工具列上的〔列印〕鈕時,開啟的列印對話窗裡面都是空白 一片,很可能是 ActiveX 元件被瀏覽器檔掉了。此時可檢查瀏覽器的安全性選項,調整與 ActiveX 有關的設定。若是 IE,特別注意「允許不提示就執行從未使用過的 ActiveX 控制項」選項必須啟用,或者更簡單,直接將 Web server 加入信任網站。

Part IV. 改成以程式餵資料給報表

在大部分的情況下,應用程式通常會讓使用者指定一些查詢條件,然後依照那些條件來查詢報表所需的資料。這裡簡單示範用網頁的 URL 帶參數的方式,將執行時期查詢的資料集餵給報表物件。步驟如下:

  1. 在 Web.config 的 ConnectionStrings 元素中加入連線設定(此步驟非必要,你當然也可以把連線字串寫在別的地方),如下所示:

    <connectionStrings>
    <add name="NorthwindConnStr" connectionString="Server=localhost;Database=Northwind;uid=sa"
    providerName="System.Data.SqlClient" />
    </connectionStrings>
  2. 撰寫 SampleRpt1.aspx 的 Page_Load 事件處理常式:

    protected void Page_Load(object sender, EventArgs e)
    {
    string customerID = Request["ID"]; // 從 URL 取出查詢參數

    string sql = "select * from Customers where CustomerID like '" + customerID + "%'";
    string cnstr = ConfigurationManager.ConnectionStrings["NorthwindConnStr"].ConnectionString;

    SqlDataAdapter da = new SqlDataAdapter(sql, cnstr);
    DataSet ds = new DataSet();
    da.Fill(ds);

    CrystalReportSource1.ReportDocument.SetDataSource(ds.Tables[0]);
    CrystalReportViewer1.ReportSource = CrystalReportSource1;
    }
  3. 在瀏覽器中檢視 SampleRpt1.aspx,注意網址要帶參數,例如:http://localhsot/DemoRpt/SampleRpt1.aspx?ID=A,這表示在產生報表時,只要列出客戶編號以字母 'A' 開頭的客戶資料。執行結果請參考圖12

討論:Push Model 與 Pull Model

Crystal Reports 的報表運作模型分為兩種:pull model 和 push model。所謂的 pull model,指的是報表的資料來源是在設計報表時就指定好的,亦即在執行時期產生報表時,會向預先指定的資料來源(通常是資料庫)將所需的資料「拉」回 來。前面 Part I 和 Part II 的範例程式就是採用 pull model。Push model 則是在執行時由程式將資料「塞」給報表,你在 Part IV 裡面看到的寫法就是採用 push model。以下兩張圖取自這篇文章:〈Creating Crystal Reports Using the Push Method in .NET〉,該文章也有範例教學可以參考。

Pull Model:

Push Model:

根據以上的描述,我們可以知道 pull model 跟 push model 在開發成本上的差異。由於 pull model 是將大部分的工作都在設計報表時完成,而 push model 還必須撰寫程式將資料塞給報表,當資料庫欄位變動時,不僅要修改報表,還得修改對應的程式碼,因此 push model 在開發的成本上會稍微麻煩些。不過 push mode 相對的也較為彈性,因為這等於是讓開發人員可以將報表資料透過程式全部都準備好之後,再利用報表工具呈現出來,這可以解決掉許多複雜的報表需球(如動態欄 位、極複雜的 SQL join 才能完成的資料查詢等)。如果採用 pull model,對一些比較複雜的報表需求,可能就得藉助 Crystal Reports 的特殊功能或撰寫Crystal Reports 專屬的指令碼來達成,而這樣就牽涉到未來維護的問題了。因此,個人比較傾向利用程式處理建立報表資料的部份,也就是 push model。

結語

本文以一個非常簡單的報表範例來說明從報表設計、程式撰寫、到部署報表的各個步驟,並簡單介紹 push model 和 pull model 兩種報表運作模式的差異,主要的目的是希望未曾用 Visual Studio 2005 開發過 Crystal Reports 報表的人能藉由 step-by-step 練習的方式,對整個報表的開發過程有個概略的認識。為了讓範例盡量簡單,Crystal Reports 的一些報表功能,像是群組、公式欄位、子報表、Drill Down......等等,這些都沒有用到,如果你需要這些設計報表的技巧,可以參考市面上的書籍和網路上的相關文章。

參考資料