首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将BlockUIContainer打印到XpsDocument/FixedDocument

将BlockUIContainer打印到XpsDocument/FixedDocument
EN

Stack Overflow用户
提问于 2012-02-25 19:33:51
回答 2查看 6.4K关注 0票数 9

问题

  1. 如何打印具有FlowDocument的BlockUIContainer
  2. 如何在FlowDocument上强制执行度量值/更新/安排?

背景

我已经生成了一个包含文本段落的FlowDocument,其中有几个来自资源字典的Rectangle元素填充了DrawingBrushes,还有一些带有自定义控件的BlockUIContainer

当文档被转换为FixedDocument/XpsDocument时,当文档被转换为FixedDocument/XpsDocument时,BlockUIContainer元素都不会呈现任何RectangleBlockUIContainer元素。

我几乎可以肯定,这是因为控件没有测量/安排,但是在转换为之前,无法弄清楚如何强制这样做。

  • 我递归地遍历了LogicalTree并完成了以下操作 UIElement元素= (UIElement)d;element.Measure(Double.PositiveInfinity,Double.PositiveInfinity);element.Arrange(新Rect(element.DesiredSize));element.UpdateLayout(); 其中dDependencyObject。我可以看到,在调试器中断点时,这会设置ActualWidthActualHeight属性。
  • 我已经尝试过强制Dispatcher按照威尔♦的建议呈现。

用于打印的XpsDocument代码

代码语言:javascript
复制
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);
    }

}

如您所见,我还使用了一个名为“FixedDocumentPaginator”的自定义DocumentPaginator;但是,我不会发布该代码,因为我怀疑这个问题是否存在,因为当它开始在GetPage(int pageNumber)中分页文档时,所有内容都已经转换为Visual,而且布局已经太晚了。

编辑

嗯。当我输入这个文件时,我突然想到,克隆的文档可能没有做Measure/Arrange/UpdateLayout

问题:如何强制在FlowDocument上进行度量/更新/安排?

我可以做的一个可能的黑客是将克隆的文档显示在一个FlowDocumentViewers中(也许是屏幕外)。

另一个可能的解决方案,我刚刚了解,但没有尝试是打电话:ContextLayoutManager.From(Dispatcher.CurrentDispatcher).UpdateLayout();

ContextLayoutManager为您遍历逻辑树并更新布局。

用于克隆文档的代码

代码语言:javascript
复制
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;
} 
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-02-27 11:47:18

将此作为其他与FlowDocument/FixedDocument/XpsDocument有类似呈现问题的人的未来参考。

有几件事要注意:

  • 使用上述方法时,不会克隆BlockUIContainers。直到我使用一些帮助方法将逻辑树打印出调试窗口(这些方法发布在下面--它们非常有用)之前,这一点并不明显。
  • 您需要在查看器中显示文档,并在屏幕上简短地显示它。下面是我为自己编写的帮助方法。

ForceRenderFlowDocument

代码语言:javascript
复制
private static string ForceRenderFlowDocumentXaml = 
@"<Window xmlns=""http://schemas.microsoft.com/netfx/2007/xaml/presentation""
          xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">
       <FlowDocumentScrollViewer Name=""viewer""/>
  </Window>";

public static void ForceRenderFlowDocument(FlowDocument document)
{
    using (var reader = new XmlTextReader(new StringReader(ForceRenderFlowDocumentXaml)))
    {
        Window window = XamlReader.Load(reader) as Window;
        FlowDocumentScrollViewer viewer = LogicalTreeHelper.FindLogicalNode(window, "viewer") as FlowDocumentScrollViewer;
        viewer.Document = document;
        // Show the window way off-screen
        window.WindowStartupLocation = WindowStartupLocation.Manual;
        window.Top = Int32.MaxValue;
        window.Left = Int32.MaxValue;
        window.ShowInTaskbar = false;
        window.Show();
        // Ensure that dispatcher has done the layout and render passes
        Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Loaded, new Action(() => {}));
        viewer.Document = null;
        window.Close();
    }
}

编辑:--我刚刚将window.ShowInTaskbar = false添加到方法中,就像您速度快一样--您可以看到窗口出现在任务栏中。

用户永远不会“看到”窗口,因为它位于Int32.MaxValue的屏幕外--这在早期多媒体创作中很常见(例如,Macromedia/Adobe )。

对于搜索和查找这个问题的人,我可以告诉您,没有其他方法可以强制文档呈现。

可视化和逻辑树帮助器

代码语言:javascript
复制
public static string WriteVisualTree(DependencyObject parent)
{
    if (parent == null)
        return "No Visual Tree Available. DependencyObject is null.";

    using (var stringWriter = new StringWriter())
    using (var indentedTextWriter = new IndentedTextWriter(stringWriter, "  "))
    {               
        WriteVisualTreeRecursive(indentedTextWriter, parent, 0);
        return stringWriter.ToString();
    }
}

private static void WriteVisualTreeRecursive(IndentedTextWriter writer, DependencyObject parent, int indentLevel)
{
    if (parent == null)
        return;

    int childCount = VisualTreeHelper.GetChildrenCount(parent);
    string typeName = parent.GetType().Name;
    string objName = parent.GetValue(FrameworkElement.NameProperty) as string;

    writer.Indent = indentLevel;
    writer.WriteLine(String.Format("[{0:000}] {1} ({2}) {3}", indentLevel, 
                                                              String.IsNullOrEmpty(objName) ? typeName : objName, 
                                                              typeName, childCount)
                    );

    for (int childIndex = 0; childIndex < childCount; ++childIndex)
        WriteVisualTreeRecursive(writer, VisualTreeHelper.GetChild(parent, childIndex), indentLevel + 1);
}

public static string WriteLogicalTree(DependencyObject parent)
{
    if (parent == null)
        return "No Logical Tree Available. DependencyObject is null.";

    using (var stringWriter = new StringWriter())
    using (var indentedTextWriter = new IndentedTextWriter(stringWriter, "  "))
    {
        WriteLogicalTreeRecursive(indentedTextWriter, parent, 0);
        return stringWriter.ToString();
    }
}

private static void WriteLogicalTreeRecursive(IndentedTextWriter writer, DependencyObject parent, int indentLevel)
{
    if (parent == null)
        return;

    var children = LogicalTreeHelper.GetChildren(parent).OfType<DependencyObject>();
    int childCount = children.Count();

    string typeName = parent.GetType().Name;
    string objName = parent.GetValue(FrameworkElement.NameProperty) as string;

    double actualWidth = (parent.GetValue(FrameworkElement.ActualWidthProperty) as double?).GetValueOrDefault();
    double actualHeight = (parent.GetValue(FrameworkElement.ActualHeightProperty) as double?).GetValueOrDefault();

    writer.Indent = indentLevel;
    writer.WriteLine(String.Format("[{0:000}] {1} ({2}) {3}", indentLevel,
                                                              String.IsNullOrEmpty(objName) ? typeName : objName,
                                                              typeName, 
                                                              childCount)
                    );

    foreach (object child in LogicalTreeHelper.GetChildren(parent))
    {
        if (child is DependencyObject)
            WriteLogicalTreeRecursive(writer, (DependencyObject)child, indentLevel + 1);
    }

}

使用

代码语言:javascript
复制
#if DEBUG
    Debug.WriteLine("--- Start -------");
    Debug.WriteLine(VisualAndLogicalTreeHelper.WriteLogicalTree(document));
    Debug.WriteLine("--- End -------");
#endif
票数 10
EN

Stack Overflow用户

发布于 2013-08-06 19:14:08

我找到了这个解决方案这里,它帮助我打印的FlowDocment,而不必渲染它的screen...So -我希望它可以帮助你!!

代码语言:javascript
复制
String copyString = XamlWriter.Save(flowDocViewer.Document);
FlowDocument copy = XamlReader.Parse(copyString) as FlowDocument;
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9447338

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档