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; }
}
}以上代码就是对控件进行了打印宽度的缩放之后实现的分页打印。
相信聪明如你一定能够看得懂。
但是问题又来了,分页打印是按照图像来进行分割,如果内容刚好在分割线上,那就是前一页打印一半,后一页打印一半,就很不好看了!
肿么办?
关注 吵吵博客
微信扫一扫关注公众号