Вопрос
- Как распечатать FlowDocument с
BlockUIContainer
?
- Как я могу принудительно измерить / обновить / расположить FlowDocument?
Фон
У меня есть сгенерированный FlowDocument
с абзацами текста с несколькими Rectangle
элементами, заполненными DrawingBrushes
из словаря ресурсов и BlockUIContainer
с пользовательскими элементами управления.
Документ отображается правильно при просмотре в любом из элементов управления FlowDocument * HOWEVER , когда документ конвертируется в 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
сделать так, как предлагает Will ♦ .
Код, используемый для печати 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
, и уже слишком поздно для макета.
Редактировать
Хм. Когда я набирал это, мне только что пришла в голову мысль, что клонированный документ 1069 *, возможно, не выполнил 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;
}