Наконец-то я понял, что есть вариант, отвечающий моему общему требованию по внедрению векторного формата в задание на печать, но он не работает с печатью на основе GDI.
Формат файла XPS, созданный драйвером печати Microsoft XPS Writer, можно распечатать из WPF с помощью библиотеки ReachFramework.dll, включенной в .NET. Используя для печати WPF вместо GDI, можно встроить страницу документа XPS в более крупный документ для печати.
Недостатком является то, что печать WPF работает немного по-другому, поэтому весь код поддержки, который напрямую использует материал в пространстве имен System.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);
}
Извините, что это не совсем компиляция кода, я просто хотел предоставить обзор фрагментов кода, необходимых для того, чтобы заставить его работать, чтобы дать другим людям преимущество во всех разрозненных фрагментах, которые должны собраться вместе, чтобы заставить его работать. Попытка создать более обобщенное решение будет намного сложнее, чем объем этого ответа.
person
Bryce Wagner
schedule
13.11.2012