在delphi或者c#时代,我们做打印程序就像是在控制一个画笔,把每个内容都绘制出来,于是乎你要精确的去计算字体的大小、输出内容左右的距离等等,恩确实是个烦心的事情。
WPF的渲染机制让WPF的打印变的相当方便,渲染引擎在控件绘制中是咋样的,打印机上就是怎么画的。
我们先看简单的控件打印的代码:
PrintDialog printDialog = new PrintDialog(); if (printDialog.ShowDialog() == true) { printDialog.PrintVisual(Mainwindow, "123"); }
我们看到,一个PrintVisual函数就完成了窗口或者说控件的打印,非常的简洁和方便。
但是当我们打印的是一个有滚动条的控件呢?例如DataGrid或者ListView,如果依旧用printVisual打印出来的就只是当前的一页而已。
这个问题如何解决,在网上找了半天的解决办法,终于搞明白了。
1、第一步是要撑开控件,让控件的实际高度ActuralHeight变成一个大于一页纸高度的数值。如果只是单纯的用datagrid,它实际的高度还是很小。
因此我们需要先用scrollviewer把它给包括起来。因为scrollviewer是可以被撑开的,所以里面的元素就可以完整的布满了,比如里面放一个StackPanel或者是没有滚动条的DataGrid,那么stackPanel的实际高度就会很大。
2、撑开控件之后,利用控件的高度除以打印页面的高度,就可以计算出来打印的页数了。但是我们还是有个问题没有解决,怎么告诉打印机应该打印哪一页呢?
答案是DocumentPaginator,可以理解为一个分页打印的容器,这个类至少要告诉打印机一共要打印多少页,每页打印的内容是什么?
每页打印的内容是由public override DocumentPage GetPage(int pageNumber)重载函数完成的。
而交给打印机打印的内容叫做DocumentPage。
DocumentPage的创建是需要传入一个Visual控件的,例如:
var page = new DocumentPage(FrameworkElement element);
于是乎就有一个问题来了,我打印的控件是同一页啊,即便我告诉打印机我要打印3页,但是每次传入的控件都是同一个stackpanel,那打印出来的东西不就是一模一样?
3、RenderTransform就是解决这个问题的关键之处了。
我们可以传入一个相同的控件,但是我们可以对它渲染引擎进行变幻,比如高度3000的stackpanel,我们可以让它从高度1000的地方开始展示,因此实际上就实现了分页的功能了。
RenderTransform有多种变幻的方式,比如放大缩小,比如旋转,比如进行平移等等。
如果既要缩小,又要平移怎么办?
用TransformGroup解决。
public class ProgramPaginator : DocumentPaginator { private FrameworkElement element; private Size printerSize; private Size scaleControlSize; public ProgramPaginator(FrameworkElement element,Size printerSize) { this.element = element; this.printerSize = printerSize; //根据宽度进行缩放 double scaleX = printerSize.Width / element.ActualWidth; double scaleY = scaleX; this.scaleControlSize = new Size(element.ActualWidth*scaleX,element.ActualHeight*scaleY); } public override DocumentPage GetPage(int pageNumber) { TransformGroup tfg = new TransformGroup(); //缩放变幻 double scaleX =printerSize.Width/ element.ActualWidth ; ScaleTransform stf=new ScaleTransform(scaleX,scaleX); tfg.Children.Add(stf); //平移变幻 TranslateTransform ttf=new TranslateTransform(0, -PageSize.Height * (pageNumber )); tfg.Children.Add(ttf); element.RenderTransform = tfg; Size elementSize =new Size(element.ActualWidth, element.ActualHeight); element.Measure(elementSize); element.Arrange(new Rect(new Point(0, 0), elementSize)); var page = new DocumentPage(element); element.RenderTransform = null; return page; } public override bool IsPageCountValid { get { return true; } } public override int PageCount { get { return (int)Math.Ceiling(this.scaleControlSize.Height / PageSize.Height); } } public override Size PageSize { get { return printerSize; } set {printerSize = value; } } public override IDocumentPaginatorSource Source { get { return null; } } }
以上代码就是对控件进行了打印宽度的缩放之后实现的分页打印。
相信聪明如你一定能够看得懂。
但是问题又来了,分页打印是按照图像来进行分割,如果内容刚好在分割线上,那就是前一页打印一半,后一页打印一半,就很不好看了!
肿么办?
如无特别说明,本博客文章皆为原创。转载请说明,来自吵吵博客。
原文链接:http://chaochaoblog.com/archives/3552
吵吵微信朋友圈,请付款实名加入: