見資源 運用.NET Framework中的類來創建看上去很專業的報表。 by Michael Eaton 技術工" name="description" />
下載本文代碼 下載本期雜志代碼 javascript:openWindowRes('VS/2002_11/xml2html.asp?xmlfile=NetPrinting/Resources.xml&xslfile=../../include/xsl/Resources.xsl')">見資源 |
你可以用幾種方法在.NET中編程來生成打印輸出結果(如報表)。對Windows程序員來說,Visual Studio提供的Crystal Reports實際上是人們常用的打印報表的工具,但對不太復雜的報表來說,這個工具就有些大材小用了。當然,你可以用很好的Win32 API調用,但是盡管API可以讓你有完全的控制權,它同時也把你鎖定到一個單一的平臺上了。如果Microsoft或另外的公司(如擁有Mono項目的Ximian公司)把Framework轉移到另外的平臺上,那么運用API的程序仍會鎖定在Windows上,除非你為新的平臺重新編寫它們。
.NET Framework可以讓你以一種新的方式來使用這些打印方法,System.Drawing.Printing名字空間的類將Win32 API的細粒度控制(fine-grain control)與相對簡單的Visual Basic傳統的Printer對象結合了起來(見表下)。
類 | 說明 |
PrintDocument | 可以讓你定義一個對象,該對象把輸出發送到一臺打印機。 |
PrintEventArgs | 為BeginPrint和EndPrint事件提供所有的必需的信息。 |
PrintPageEventArgs | 為PrintPage事件提供所有必需的信息。 |
QueryPageSettingsEventArgs | 為QueryPageSettings事件提供信息。 |
PrintController | 控制一個PrintDocument是如何打印的。 |
StandardPrintController | 派生于PrintController。 |
PreviewPrintController | 派生于PrintController。 |
PreviewPageInfo | PreviewPrintController 經常運用這個類。它為一個單獨的頁面指定了預覽信息。 |
PageSettings | 指定一個單獨的打印頁面的設置。 |
Margins | 可以讓你指定一個打印頁面的頁邊距。頁面的頂部、左邊、右邊和底部邊距屬性是以英寸(×100)的形式返回的。 |
MarginsConverter | 可以讓你把一個Margins對象轉換成另外的類型,把另外的類型轉換成一個Margins對象。 |
PaperSize | 指定一頁紙的大小。當同一個PageSettings對象一起使用時,它指的是一個頁面的紙張大小。當用于PrinterSettings時,它可以讓你得到打印機上可以用的紙張大小。 |
PaperSizeCollection | PaperSize對象的一個集合。 |
PaperSource | 像PaperSize類一樣, PaperSource 是由一個PageSettings對象和一個PrinterSettings對象使用的。當用于PageSettings時,它可以讓你為一個特定頁面得到紙張來源。當用于PrinterSettings時,它可以讓你得到打印機運用的所有紙張來源。 |
PaperSourceCollection | PaperSource 對象的一個集合。 |
PrinterSettings | 指定一個文件是如何打印的,包括文件在哪個打印機上打印。它是與特定的PrintDocument相應的。 |
PrinterResolution | 可以讓你得到橫向的和縱向的DPI,以及實際的打印機分辨率(draft, high, low, 等等)。 |
PrinterResolutionCollection | PrinterResolution 對象的一個集合。 |
InvalidPrinterException | 表示將拋出的異常(如果你用無效的設置來訪問一臺打印機)。 |
PrintingPermission | 控制對打印機的使用權限。 |
PrintingPermissionAttribute | 允許檢測打印權限。 |
表 1 研究 .NET的眾多的打印類.
運用.NET Framework的System.Drawing.Printing名字空間,你就可以程序化地處理許多打印任務,該名字空間包含20多個類、7個枚舉類型和3個委托類型(delegate)。讓我們來看看對每個類的簡要說明吧!
在此,我將重點講述該名字空間的主要的類,它們可以讓你創建復雜程度適度的報表。PrintDocument類是這些類中最重要的。它可以讓你定義一個對象,該對象發送輸出結果到一個目的地,可以是一臺打印機,或者是顯示一個打印預覽(運用PrintPreviewDialog類)。我還會講述PrinterSettings類,它可以讓你控制文件是如何打印的。
你可以很容易地在C#中創建一個PrintDocument對象,并把它附到一個事件處理程序上(實際處理打印的代碼):
PrintDocument doc = new PrintDocument(); doc.PrintPage += new PrintPageEventHandler( doc_PrintPage); |
PrintPage事件處理程序有一個PrintPageEventArgs類型的參數。這個參數包含與該事件相關的數據,包括當前頁面的頁面設置、頁邊距信息以及是否有更多的頁需要打印。每個頁面觸發該事件一次,直到ev.HasMorePages等于false:
private void doc_PrintPage(object sender, PrintPageEventArgs ev) |
將Graphics用于Fonts和Fills
ev參數引用了你用來輸出數據的Graphics制圖區。Graphics有用來打印圖象、文本、形狀和線條的方法。你可以用DrawString方法來定義你要用的font(字體)和brush(畫刷)。一個brush定義了一個圖形的內部是如何填充的。你也需要告訴DrawString方法你想在哪里打印文本。PrintPageEventArgs類有一個讀寫屬性——HasMorePages——它指明是否需要打印更多的頁面:
Font f = new Font("Arial", 12); ev.Graphics.Drawstring("Hello, World.", f, Brushes.Black, 100, 100); ev.HasMorePages = false; |
現在,你已經創建了一個PrintDocument對象并把它和一個事件處理程序聯系起來了。你已經給事件處理程序中添加了代碼,來打印一個單獨的字符串,它的位置是距頁面左邊一英寸、距頁面頂部一英寸,用的是12磅、 Arial的字體?,F在我們來打印文件:
doc.Print(); |
在缺省設置下,PrintDocument類的Print方法在缺省打印機上打印結果,除非你另外指定。你可以用PrintDialog類來另外指定,它是System.Windows.Forms.CommonDialog名字空間的一部分。PrintDialog可以讓你選擇打印機,選擇打印文件的哪部分,選擇打印份數,來隨意地打印一個文件。
PrintDialog類的PrinterSettings屬性可以讓你將諸如copies、from page和to page的屬性放置到一個特定文件的PrinterSettings對象中。換句話說,單獨的PrintDocument對象有一個PrinterSettings對象,它指定打印的份數、打印的范圍、要運用的打印機的名字以及關于打印機本身的信息。
IPrinterSettings類中的一個bug會導致Copies屬性總是返回一個為1的值,而不管你在PrintDialog中輸入了多少份數。然而,PrintDocument.Print()方法仍然打印正確的份數,所以只有當你想將這個值用于其它地方時,才顯示這個bug。當你執行Print方法時,系統運用這些設置。你可以提供一個實際的PrinterSettings對象或提供一個Document對象:
PrintDialog pd = new PrintDialog(); pd.Document = doc; pd.ShowDialog(); |
然后,運用CommonDialog名字空間的PageSetupDialog,你可以指定紙張大小、紙張來源、打印方向和頁邊距。PageSetupDialog和PrintDialog都需要你提供一個Document對象或一個PageSettings對象。PageSettings對象適用于一個單獨的打印頁面,可以處理頁邊距、紙張大小以及是否用顏色打印頁面:
PageSetupDialog ps = new PageSetupDialog(); ps.Document = doc; ps.ShowDialog(); |
打印一個文件
當然,許多應用程序打印存儲在一個文件或某種數據庫中的信息,所以現在我將講述一個更復雜的例子:打印一個以逗號分隔的聯系清單文本文件。你可以將一個數據集、甚至一個XML文件中數據所運用的方法用在這里。本例的數據來自Northwind數據庫的Customers表,格式如下:
Name, Title, Phone, Fax |
通過在類的級別聲明一個StreamReader對象,然后將一個文件分配給它,你就可以從一個文本文件打印該例子了。打開文件,修改PrintPage事件處理程序來打印文件的每一行,按需要格式化數據。
PrintDocument類有好幾個事件。你已經用了PrintPage事件了;現在我們來添加更多的事件。當開始一個打印任務時(在實際打印任何東西前),觸發BeginPrint事件。相應的事件是EndPrint,該事件是在所有頁面結束打印時觸發的。創建PrintPage事件需要的任何對象,或在BeginPrint中打開任何數據源,然后在EndPrint中關閉或釋放(deallocate)它們。不要忘記將這些事件綁定到PrintDocument對象(見下)。
C#:創建和部署
列表 1.
PrintDocument對象提供了幾個事件。BeginPrint是在實際打印頁面前觸發的,可以給你提供機會來配置對象或打開文件。EndPrint在打印完最后一頁時觸發。不要忘記將事件綁定到你的PrintDocument對象。
|
![]() |
|
C#:繼承 PrintDocument
列表 2.
從PrintDocument派生一個新類,這樣你就可以把所有打印功能封裝在一個單獨的地方,從而提高代碼的重用性。
|
PrintDocument類沒有制圖工具,所以創建報表需要花些時間——但這是值得的。創建一個新的報表的最好的方法是用一張空白的紙。在了解了報表的目的后,你就可以在紙上通過畫方框來代表不同的區域進行設計了,如頁眉、正文和頁腳(見下)。
圖 1. 顯示你的報表
在定義了你的Rectangle對象后,你只需要用DrawRectangle方法寫一行代碼,用你選擇的畫筆在屏幕上畫一個長方形邊框就行了。
然后花些時間詳細編寫每個區域的數據將來自哪里,以及各個數據將放置在什么位置??梢哉f這個時候是你確保最終用戶所看到的頁面與你設計的頁面是否是一致的最佳時刻。用戶對報表比對應用程序的任何部分的挑剔都要多,所以你應該盡可能多花些時間來設計它。一旦你花了很多時間來設計報表并對它的打印結果了如指掌后,那么寫代碼就不會花很多時間了。
原文轉自:http://www.anti-gravitydesign.com