Вопрос
- Как распечатать FlowDocument с
BlockUIContainer
? - Как я могу принудительно выполнить измерение / обновление / упорядочение в FlowDocument?
Фон
У меня есть сгенерированный FlowDocument
с абзацами текста с несколькими Rectangle
элементами, заполненными DrawingBrushes
из словаря ресурсов и BlockUIContainer
с настраиваемыми элементами управления.
Документ отображается правильно при просмотре в любом из элементов управления FlowDocument * ОДНАКО, когда документ преобразован в FixedDocument / XpsDocument, ни один из элементов Rectangle
или BlockUIContainer
не отображается.
Я почти уверен, что это связано с тем, что элемент управления не был измерен / размещен, однако не могу понять, как заставить это произойти, прежде чем он будет преобразован в XpsDocument.
Я прошел
LogicalTree
рекурсивно и сделал следующее:UIElement element = (UIElement)d; element.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity)); element.Arrange(new Rect(element.DesiredSize)); element.UpdateLayout();
где
d
- этоDependencyObject
. Я вижу, что это устанавливает свойстваActualWidth
иActualHeight
при установке точки останова в отладчике.Я попытался заставить
Dispatcher
отображаться, как это было предложено Будет ♦.
Код, используемый для печати XpsDocument
public class XpsDocumentConverter
{
public static XpsDocumentReference CreateXpsDocument(FlowDocument document)
{
// Need to clone the document so that the paginator can work
FlowDocument clonedDocument = DocumentHelper.Clone<FlowDocument>(document);
Uri uri = new Uri(String.Format("pack://temp_{0}.xps/", Guid.NewGuid().ToString("N")));
MemoryStream ms = new MemoryStream();
Package pkg = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite);
PackageStore.AddPackage(uri, pkg);
XpsDocument xpsDocument = new XpsDocument(pkg, CompressionOption.Normal, uri.AbsoluteUri);
XpsSerializationManager rsm = new XpsSerializationManager(new XpsPackagingPolicy(xpsDocument), false);
DocumentPaginator paginator = new FixedDocumentPaginator(clonedDocument, A4PageDefinition.Default);
rsm.SaveAsXaml(paginator);
return new XpsDocumentReference(ms, xpsDocument);
}
}
Как видите, я также использую пользовательский DocumentPaginator
с именем «FixedDocumentPaginator»; однако я не буду публиковать этот код, поскольку сомневаюсь, что проблема существует, поскольку к тому времени, когда он начинает разбивать документ на страницы в GetPage(int pageNumber)
, все уже было преобразовано в Visual
, и уже слишком поздно для макета.
Изменить
Хм. Когда я это набирал, мне пришла в голову мысль, что клонированный документ, возможно, не был Measure/Arrange/UpdateLayout
выполнен.
Вопрос: Как я могу принудительно выполнить измерение / обновление / упорядочение в FlowDocument?
Возможный взлом, с которым я мог бы работать, - это показать клонированный документ в одном из FlowDocumentViewers (возможно, за пределами экрана).
Другое возможное решение, о котором я только что узнал и не пробовал, - это позвонить: ContextLayoutManager.From(Dispatcher.CurrentDispatcher).UpdateLayout();
ContextLayoutManager
просматривает логическое дерево за вас и обновляет макет.
Код, использованный для клонирования документа
public static FlowDocument Clone(FlowDocument originalDocument)
{
FlowDocument clonedDocument = new FlowDocument();
TextRange sourceDocument = new TextRange(originalDocument.ContentStart, originalDocument.ContentEnd);
TextRange clonedDocumentRange = new TextRange(clonedDocument.ContentStart, clonedDocument.ContentEnd);
try
{
using (MemoryStream ms = new MemoryStream())
{
sourceDocument.Save(ms, DataFormats.XamlPackage);
clonedDocumentRange.Load(ms, DataFormats.XamlPackage);
}
clonedDocument.ColumnWidth = originalDocument.ColumnWidth;
clonedDocument.PageWidth = originalDocument.PageWidth;
clonedDocument.PageHeight = originalDocument.PageHeight;
clonedDocument.PagePadding = originalDocument.PagePadding;
clonedDocument.LineStackingStrategy = clonedDocument.LineStackingStrategy;
return clonedDocument;
}
catch (Exception)
{
}
return null;
}