用WPF打印页眉和页脚
在《用WPF实现打印和打印预览》一文中,我提供的程序有个问题,就是不能方便地打印页眉和页脚,而很多时候我们需要加入页眉也页脚,比如我们给客户打印一个订单列表,我们希望在输出的每页中加入公司名称和页码数,这个如何实现呢?
这个看起来似乎比较难:想知道要在什么地方插入页眉也页脚,我们就需要知道在哪里分页,而插入页眉和页脚势必会占用一些页面空间,使得打印页面变得比之前狭窄,分页点也会随之发生变化……这貌似是一个鸡生蛋,蛋生鸡的死循环。后来参考了一些国外的blog,终于找到了解决方案,大家先看看这是我的效果图:
页眉和页脚都有了。它的实现原理其实并不复杂,看下图就很清楚了:
我们当然是用WPF默认的流文档分页器来对我们要打印的内容进行分页(在前一篇我提到过自己实现一个分页算法几乎是Mission Impossible),然后把默认要打印的各个页面“压缩”一下,在上面腾出一点空间来给页眉,在下面腾出一点空间来给页脚。
我们在代码中要做的事情就是自行实现一个Paginator,取代FlowDocument默认的DocumentPaginator,override其GetPage方法,在这个方法里做点手脚,就是前面提到的把页面“压缩”一下,上插页眉,下插页脚。代码如下:
public class PaginatorHeaderFooter : DocumentPaginator { readonly DocumentPaginator m_paginator; public PaginatorHeaderFooter(DocumentPaginator paginator) { m_paginator = paginator; } public override DocumentPage GetPage(int pageNumber) { DocumentPage page = m_paginator.GetPage(pageNumber); ContainerVisual newpage = new ContainerVisual(); //页眉:公司名称 DrawingVisual header = new DrawingVisual(); using (DrawingContext ctx = header.RenderOpen()) { FormattedText text = new FormattedText("上海ABCD信息技术有限公司", System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Courier New"), 14, Brushes.Black); ctx.DrawText(text, new Point(page.ContentBox.Left, page.ContentBox.Top)); ctx.DrawLine(new Pen(Brushes.Black, 0.5), new Point(page.ContentBox.Left, page.ContentBox.Top+16), new Point(page.ContentBox.Right, page.ContentBox.Top+16)); } //页脚:第几页 DrawingVisual footer = new DrawingVisual(); using (DrawingContext ctx = footer.RenderOpen()) { FormattedText text = new FormattedText("第" + (pageNumber+1) + "页", System.Globalization.CultureInfo.CurrentCulture, FlowDirection.RightToLeft, new Typeface("Courier New"), 14, Brushes.Black); ctx.DrawText(text, new Point(page.ContentBox.Right, page.ContentBox.Bottom-20)); } //将原页面微略压缩(使用矩阵变换) ContainerVisual mainPage = new ContainerVisual(); mainPage.Children.Add(page.Visual); mainPage.Transform = new MatrixTransform(1, 0, 0, 0.95, 0, 0.025 * page.ContentBox.Height); //在现页面中加入原页面,页眉和页脚 newpage.Children.Add(mainPage); newpage.Children.Add(header); newpage.Children.Add(footer); return new DocumentPage(newpage, page.Size, page.BleedBox, page.ContentBox); } //省略掉一些代码 }
代码我想已经很清晰了,唯一需要说一下的是“压缩”原始页面所使用的那个MatrixTransform,其实学过计算机图形学的同学一定不会陌生,但对我这个非科班出身的人来说,一开始还有些迷惑,过去学线性代数的时候老师也从来不说那些知识是可以用于图形学上的图形变换(糟糕的中国教育啊……),这个3*3的矩阵可用于对2D图形的缩放,平移和旋转,具体可以参考这篇文章:点击打开。
在之前的那个流文档模版里加入一个资源,True表示打印页眉和页脚,False表示不打印。
<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" ColumnWidth="400" FontSize="14" FontFamily="宋体" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:core="clr-namespace:System;assembly=mscorlib" TextOptions.TextFormattingMode="Display"> <FlowDocument.Resources> <core:Boolean x:Key="PrintHeaderAndFooter">True</core:Boolean> </FlowDocument.Resources> <!-- 省略 --> </FlowDocument>
本来我还打算把页眉和页脚的内容整合到流文档模版里,(现在的做法是写死在Paginator中的)但貌似有些难度,这个任务你可以尝试一下。
代码下载:完整代码(VS2010)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人