WPF分页打印控件所有内容

 

在delphi或者c#时代,我们做打印程序就像是在控制一个画笔,把每个内容都绘制出来,于是乎你要精确的去计算...



在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; }

}

}以上代码就是对控件进行了打印宽度的缩放之后实现的分页打印。

相信聪明如你一定能够看得懂。

但是问题又来了,分页打印是按照图像来进行分割,如果内容刚好在分割线上,那就是前一页打印一半,后一页打印一半,就很不好看了!

肿么办?


    关注 吵吵博客


微信扫一扫关注公众号

0 个评论

要回复文章请先登录注册