发布一个自己写的PrintPreviewControl自定义控件,支持鼠标滚轮,源代码下载。

先说一下上次发布的 “ 发布一个支持大量文本打印的PrintDocument派生对象,公开源代码”
的文章,我发布了一个继承与System.Drawing.Printing.PrintDocument的对象,这个对象支持从文件流和文本字符串内生成打印作业文档,当时我没有仔细测试,发现其中有一个很大的逻辑bug。

bug的表现是假如你使用字符串赋值的办法生成对象实例,那么打印预览的时候你会惊奇的发现预览的时候文档内容打印了两遍。而我后来才发现这个问题。

经过查找,我发现了原因,但这个原因很奇妙。
原理是,我为了一次读取一行文本,我使用了System.IO.StringReader类作为读取器。而它的构造函数就是传递进来的保存文本内容的字符串,然后使用 StringReader.ReadLine() 方法来读取文本,生成打印的内容。

但是我必须要实现一个机制,这个机制用来检查读取器是否读取到最后的内容,而StringReader.Peek()方法就是检测后面是否有内容,如果没有内容就返回-1值。而经过我的测试,无论是否怎样检测,都不返回-1,而是把内容输入两遍后才返回-1,这样就导致同样的内容显示了两遍。

这个bug已经修改,我通过其他的办法修改了检测手段,这次无需打两次内容了。请下载的各位重新下载一次。


现在开始说PrintPreveiwControl控件。

首先要提醒大家注意的是,它是一个自定义windows 控件,而不是新的打印预览窗口。它就是打印预览窗口中显示打印预览的那部分内容,如果大家要使用的话,必须建立一个windows窗体,然后使用它既可。

说实话,微软在.net中自带的打印预览窗口非常不好,即不好看,也不好用,所以微软就提供了一个System.Windows.Forms.PrintPreviewControl控件,而这个控件也不太好,主要是不支持鼠标滚轮,另外最重要的就是不支持打印页面计数,而打印预览时的可用页面数目是打印预览窗口中“上页”,“下页”这样的按钮所必须的属性。

所以我使用了Reflector反编译了微软的PrintPreviewControl控件,使用它的原始代码并添加了“OnMouseWheel”事件处理程序,而OnMouseWheel就是专门处理鼠标滚轮滚动时的操作的。同样公布源代码。

OnMouseWheel方法内我添加了大量注释,有要处理鼠标滚轮的朋友可以根据这个代码的原理来发挥。

下载: 单击此处下载

另外:
上次的TextPrintDocument我也添加了大量注释,大家可以参考。

posted on 2006-08-11 18:06 笑望人生 阅读(5568) 评论(10) 编辑 收藏

评论

#1楼  回复 引用 查看   

需要一个表格打印的东西,我自己写了一个文本及DataGridView的打印处理类,是与PrintDocument配合使用,带有表格自动换页等功能,文本可支持自己定义打印模板
2006-08-12 03:12 | Pvistely      

#2楼  回复 引用   

打印表格源码,DataGrid/View、ListView二维数据全部搞定
http://www.webmis.com.cn/misgoldprinter.htm
2006-08-12 10:33 | 长江支流[未注册用户]

#3楼  回复 引用 查看   

如果楼主能写一个bs的那就更伟大了
2006-08-13 09:32 | aspnetx      

#4楼  回复 引用   

看代码感觉像是反编译出来的,主要是看PrintPreviewControl中的WmKeyDown方法,不知道对不对,呵呵。
2006-08-13 22:38 | wlj[未注册用户]

#5楼  回复 引用 查看   

怎么都没人顶呢?支持楼主开源,不错,学习学习。。
2006-08-14 08:03 | phinecos(洞庭散人)      

#6楼[楼主]  回复 引用 查看   

对,是反编译出来的。
我是把微软在.Net中的PrintPreviewControl的源代码反编译出来后,自己添加的代码。

这么做的原因是我必须要实现PageCount 只读属性。
这个属性的含义是当打印预览的内容经过处理显示在窗口后,可以从这个属性获取总共有多少页。
在根据已有的StartPage属性(当前页索引)这个属性,就可以实现打印预览中“上一页”,“下一页”这样的工具栏按钮了,而且使用鼠标滚轮翻页时也容易计算。

经过我分析微软的PrintPreviewControl控件代码,发现页面属性是使用微软的一个内部变量PreviewPageInfo数组提供的,而这个数组的访问是OnPaint执行的时候建立的,我试验过,如果我自己继承微软的PrintPreviewControl后,无法按照微软的方法来建立这个数组。

建立PreviewPageInfo数组的方法是在ComputePreview()方法内。原理是微软的System.Drawing.Printing空间内有两个很重要的类:
PreviewPrintController 和 PrintControllerWithStatusDialog

PreviewPrintController 好理解,打印预览时使用的打印控制器,而PrintControllerWithStatusDialog 就是一个虚拟的打印机,他的工作与真正的打印机一样,根据PrintDocument生成打印文档,与真正打印机不同的是,PrintControllerWithStatusDialog 并不把内容输出到纸张或者硬盘文件什么地方,而是保存在内存中。

然后通过 PreviewPrintController.GetPreviewPageInfo()方法获取这些图像。获取的图像引用就是PreviewPageInfo对象数组。然后OnPaint方法直接把这些对象数组中保存的图像画在控件内,就看见内容了。
2006-08-14 11:15 | 笑望人生      

#7楼[楼主]  回复 引用 查看   

to aspnetx:
我这个控件应该可以使用在WebForm中。只要处理三个问题:

1 把此控件封装在一个dll中。

2 当控件显示在客户端IE内的时候,处理好PrintDocument对象从服务器端到客户端的序列化传输问题,即如何获取对象并显示。

3 解决控件在客户端显示的安全问题。如数字证书,强名称,或者使用安全声明等手段。
2006-08-14 11:20 | 笑望人生      

#8楼  回复 引用   

你好,下载你的源码编译怎么找不到Sanxing.Share.Properties,谢谢了
2006-11-27 16:11 | battleax[未注册用户]

#9楼  回复 引用   

我没有编译过,不过知道是在vs2005下的.我想编译过去以后我也不能用,不过还是谢谢.我会慢慢研究的.
2006-12-05 16:14 | hxy31861[未注册用户]

#10楼  回复 引用   

看了你的文章,觉得你一定是个高手。
我对自定义控件还不是很熟悉。
所以想询问一个相关问题。
.NET中,追加了一个自定义的控件后。
在窗体中,选中该控件,按F1显示出的帮助文件,
怎么才能改成自己编写的帮助文件呢。
2006-12-11 17:17 | hq[匿名][未注册用户]