扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
你可以用几种方法在.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对象结合了起来(见表下)。
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 |
|
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对象并把它和一个事件处理程序联系起来了。你已经给事件处理程序中添加了代码,来打印一个单独的字符串,它的位置是距页面左边一英寸、距页面顶部一英寸,用的是
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对象(见下)。
作为选择,你也可以把所有的打印功能封装到PrintDocument派生的一个单独的类中,然后重载触发相应事件的方法。你可以用你自定义的类,而不用实例化一个PrintDocument对象(见列下)。这是一个很好的方法,但是为了保持一致,使代码清晰,我将继续讲述事件绑定方法。
C#:继承 PrintDocument 列表 2. 从PrintDocument派生一个新类,这样你就可以把所有打印功能封装在一个单独的地方,从而提高代码的重用性。
|
PrintDocument类没有制图工具,所以创建报表需要花些时间――但这是值得的。创建一个新的报表的最好的方法是用一张空白的纸。在了解了报表的目的后,你就可以在纸上通过画方框来代表不同的区域进行设计了,如页眉、正文和页脚(见下)。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者