我终于发现有一个选项可以满足我将矢量格式嵌入打印作业的一般要求,但它不适用于基于 GDI 的打印。
可以使用 .NET 中包含的 ReachFramework.dll 从 WPF 打印由 Microsoft XPS Writer 打印驱动程序创建的 XPS 文件格式。通过使用 WPF 代替 GDI 进行打印,可以将 XPS 文档页面嵌入到更大的打印文档中。
缺点是,WPF 打印的工作方式有很大不同,因此所有直接使用 Sytem.Drawing 命名空间中内容的支持代码都必须重新编写。
下面是如何嵌入 XPS 文档的基本概述:
打开文档:
XpsDocument xpsDoc = new XpsDocument(filename, System.IO.FileAccess.Read);
var document = xpsDoc.GetFixedDocumentSequence().DocumentPaginator;
// pass the document into a custom DocumentPaginator that will decide
// what order to print the pages:
var mypaginator = new myDocumentPaginator(new DocumentPaginator[] { document });
// pass the paginator into PrintDialog.PrintDocument() to do the actual printing:
new PrintDialog().PrintDocument(mypaginator, "printjobname");
然后创建 DocumentPaginator 的后代,它将执行您的实际打印。重写抽象方法,特别是 GetPage 应该以正确的顺序返回 DocumentPages。这是我的概念验证代码,它演示了如何将自定义内容附加到 Xps 文档列表中:
public override DocumentPage GetPage(int pageNumber)
{
for (int i = 0; i < children.Count; i++)
{
if (pageNumber >= pageCounts[i])
pageNumber -= pageCounts[i];
else
return FixFixedPage(children[i].GetPage(pageNumber));
}
if (pageNumber < PageCount)
{
DrawingVisual dv = new DrawingVisual();
var dc = dv.Drawing.Append();
dc = dv.RenderOpen();
DoRender(pageNumber, dc); // some method to render stuff to the DrawingContext
dc.Close();
return new DocumentPage(dv);
}
return null;
}
当尝试打印到另一个 XPS 文档时,它给出了一个异常“FixedPage 不能包含另一个 FixedPage”,H.Alipourian 的帖子演示了如何修复它:http://social.msdn.microsoft.com/Forums/da/wpf/thread/841e804b-9130-4476-8709-0d2854c11582
private DocumentPage FixFixedPage(DocumentPage page)
{
if (!(page.Visual is FixedPage))
return page;
// Create a new ContainerVisual as a new parent for page children
var cv = new ContainerVisual();
foreach (var child in ((FixedPage)page.Visual).Children)
{
// Make a shallow clone of the child using reflection
var childClone = (UIElement)child.GetType().GetMethod(
"MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic
).Invoke(child, null);
// Setting the parent of the cloned child to the created ContainerVisual
// by using Reflection.
// WARNING: If we use Add and Remove methods on the FixedPage.Children,
// for some reason it will throw an exception concerning event handlers
// after the printing job has finished.
var parentField = childClone.GetType().GetField(
"_parent", BindingFlags.Instance | BindingFlags.NonPublic);
if (parentField != null)
{
parentField.SetValue(childClone, null);
cv.Children.Add(childClone);
}
}
return new DocumentPage(cv, page.Size, page.BleedBox, page.ContentBox);
}
很抱歉,这不是完全编译代码,我只是想概述一下使其工作所需的代码片段,以便其他人在所有需要组合在一起以使其工作的不同部分上抢占先机。尝试创建一个更通用的解决方案将比此答案的范围复杂得多。