近期的一个项目需对数据进行套打,用户要求现场不允许安装office、页面预览显示必须要与文档完全一致,xps文档来对数据进行处理。Wpf的DocumentView 控件可以直接将数据进行显示,xps也是一种开放式的文档,如果我们能够替换里面的标签就最终实现了我们想要的效果。
推荐两篇关于xps的文档介绍
废话不多说,上代码
private void setPage() { string xpsFile = "d:\\test.xps";//读取模板 XpsDocument xpsDoc = new XpsDocument(xpsFile, FileAccess.Read); FixedDocumentSequence fds = xpsDoc.GetFixedDocumentSequence(); foreach (DocumentReference DocRef in fds.References) { bool bForceReload = false; FixedDocument DocFd = DocRef.GetDocument(bForceReload); foreach (PageContent DocFpPc in DocFd.Pages) { FixedPage DocFp = DocFpPc.GetPageRoot(bForceReload); Canvas containCanvas = new Canvas(); //在页面上画一个大的图层 containCanvas.Width = DocFp.Width; containCanvas.Height = DocFp.Height; containCanvas.Background = Brushes.Transparent;//设置透明色 #region MyRegion for (int i = 0; i < DocFp.Children.Count; i++) { UIElement DocFpUiElem = DocFp.Children[i]; if (DocFpUiElem is Glyphs) { Glyphs gps = (Glyphs)DocFpUiElem; string strMark = gps.UnicodeString; if (strMark=="{1}")//判定当前数据是否为标签 { double x = gps.OriginX; double y = gps.OriginY; double fontSize = gps.FontRenderingEmSize; strMark = strMark.Replace("{ ", "").Replace("}", ""); DocFp.Children.RemoveAt(i);//移除标签 TextBlock label = new TextBlock(); Canvas.SetLeft(label, x); Canvas.SetTop(label, y - fontSize); Canvas.SetZIndex(label, 99); label.Foreground = Brushes.Red; label.FontFamily = new System.Windows.Media.FontFamily("宋体"); label.FontSize = fontSize; label.Text = "你的内容"; containCanvas.Children.Add(label); } } } #endregion DocFp.Children.Add(containCanvas);//将画布添加到页面上 ((IAddChild)DocFpPc).AddChild(DocFp); } } this.docView.Document = fds; xpsDoc.Close();//这个地方需要注意关闭,否则的话会出现莫名其妙的错误 }
处理过程中的几点注意事项:
1、关于xps文档的生成,我是采用的word2010,然后使用打印功能生成的xps文档。
2、关于标签的设置:如果在word 中你直接写{@Name } 的话,在页面中未必能够按照你的想法生成标签。我用的方法是,对于同一行、相邻的标签,需要用不同的颜色来进行标记。标记的颜色也要与正文的颜色区分开,关于xps生成的规则还不太清楚,好像只有相同字体的内容都会分到一起。如下图
3、查看标记是否正确,可以先把xps文档的后缀名修改一下,然后用winrar解压,查看解开目录 \Documents\1\Pages\1.fpage ,用记事本打开,查找一下确定标签是否正确。
如下图:
其中X.fpage是指的第几页。
标签的样式如下:
请注意,这样的解压是单向的,处理前请备份。
4、需要引用的dll文件:
WindowsBase.dll PresentationCore.dll ReachFramework.dll PresentationFramework.dll ,(部分文件在wpf中已经被引用了),光确定用需要引用那些文件都折腾了我半天,丢人啊。
经过最近几天的折腾,我认为这种方法的优点:
1、纯矢量绘图,无失真,模板上面随意画。
2、xps模板一旦做好了,交付用户,用户一般无法自己进行修改,比较简单方便。
3、不需要安装任何第三方插件。
4、任何元素,想加就加,完全可以画图、添加水印等
5、字体不会丢失,xps文件在打包的时候,会一并将字体打包进项目里面,不管安装到任何地方,都不需要考虑字体问题
代码下载:
另外,在处理模板的时候,如果使用wps212可能会有惊喜!