7

我在获取 FlowDocument 中包含的图像以显示 FlowDocument 何时保存为 XPS 文档时遇到了一些困难。

这是我所做的:

  1. 使用WPF的Image控件创建图像。我设置了通过调用 BeginInit/EndInit 括起来的图像源。
  2. 将图像添加到 FlowDocument 中,将其包装在BlockUIContainer中。
  3. 使用此代码的修改版本将 FlowDocument 对象保存到 XPS 文件。

如果我随后在 XPS 查看器中查看保存的文件,则不会显示图像。问题是图像在 WPF 实际显示在屏幕上之前不会加载,因此它们不会保存到 XPS 文件中。因此,有一个解决方法:如果我首先使用FlowDocumentPageViewer在屏幕上显示文档,然后保存 XPS 文件,则图像会加载并显示在 XPS 文件中。即使 FlowDocumentPageViewer 被隐藏,这也有效。但这给了我另一个挑战。这是我想做的(在伪代码中):

void SaveDocument()
{
    AddFlowDocumentToFlowDocumentPageViewer();
    SaveFlowDocumentToXpsFile();
}

这当然不起作用,因为在将文档保存到 XPS 文件之前,FlowDocumentPageViewer 从来没有机会显示其内容。我尝试将 SaveFlowDocumentToXpsFile 包装在对 Dispatcher.BeginInvoke 的调用中,但它没有帮助。

我的问题是:

  1. 我可以在保存 XPS 文件之前以某种方式强制加载图像而不实际在屏幕上显示文档吗?(我尝试摆弄BitmapImage.CreateOptions没有运气)。
  2. 如果问题 #1 没有解决方案,有没有办法告诉 FlowDocumentPageViewer 何时完成加载其内容,以便我知道何时保存以创建 XPS 文件?
4

4 回答 4

3

最终的解决方案与您的想法相同,即将文档放在查看器中并在屏幕上简要显示。下面是我为我写的帮助方法。

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 Director)的常见技巧。

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

高温下,

于 2012-02-27T11:37:11.250 回答
1

几件事...您确定图像在写入之前已调整大小吗?通常您必须在控件上调用 Measure 以便它可以相应地调整自身大小(无穷大让控件扩展到其宽度和高度)

image.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

此外,有时您必须碰撞 UI 线程,以便控件中的所有内容都得到更新

Dispatcher.Invoke(DispatcherPriority.Render, new Action(() =>{}));
于 2011-01-18T19:18:33.540 回答
0

您不必为了将图像保存到 xps 中而显示文档。你是在 XpsSerializationManager 上调用 commit 吗?

FlowDocument fd = new FlowDocument();

        fd.Blocks.Add(new Paragraph(new Run("This is a test")));

        string image = @"STRING_PATH";

        BitmapImage bi = new BitmapImage();
        bi.BeginInit();
        bi.UriSource = new Uri(image, UriKind.RelativeOrAbsolute);
        bi.CacheOption = BitmapCacheOption.OnLoad;
        bi.EndInit();
        MemoryStream ms = new MemoryStream();
        Package pkg = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite);
        Uri pkgUri = bi.UriSource;

        PackageStore.AddPackage(pkgUri, pkg);


        Image img = new Image();
        img.Source = bi;

        BlockUIContainer blkContainer = new BlockUIContainer(img);

        fd.Blocks.Add(blkContainer);


        DocumentPaginator paginator = ((IDocumentPaginatorSource)fd).DocumentPaginator;

      using (XpsDocument xps = new XpsDocument(@"STRING PATH WHERE TO SAVE FILE", FileAccess.ReadWrite, CompressionOption.Maximum))
        {
            using (XpsSerializationManager serializer = new XpsSerializationManager(new XpsPackagingPolicy(xps), false))
            {
                serializer.SaveAsXaml(paginator);
                serializer.Commit();
            }
        }
于 2012-03-12T13:38:44.627 回答
0

我可以通过将流文档放入查看器中来解决这个问题,然后进行测量/排列。

FlowDocumentScrollViewer flowDocumentScrollViewer = new FlowDocumentScrollViewer();
flowDocumentScrollViewer.Document = flowDocument;
flowDocumentScrollViewer.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
flowDocumentScrollViewer.Arrange(new Rect(new Point(0, 0), new Point(Double.MaxValue, Double.MaxValue)));
于 2020-01-16T01:06:49.813 回答