Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Missing images in FlowDocument saved as XPS document

I am having some difficulties getting images contained in a FlowDocument to show when the FlowDocument is saved as an XPS document.

Here is what I do:

  1. Create an image using the Image control of WPF. I set the image source bracketed by calls to BeginInit/EndInit.
  2. Add the image to the FlowDocument wrapping it in a BlockUIContainer.
  3. Save the FlowDocument object to an XPS file using a modified version of this code.

If I then view the saved file in the XPS viewer, the image is not shown. The problem is that the images are not loaded until actually shown on the screen by WPF so they are not saved to the XPS file. Hence, there is a workaround: If I first show the document on screen using the FlowDocumentPageViewer and then save the XPS file afterwards, the image is loaded and shows up in the XPS file. This works even if the FlowDocumentPageViewer is hidden. But that gives me another challenge. Here is what I wish to do (in pseudocode):

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

This of course does not work since the FlowDocumentPageViewer never gets a chance to show its contents before the document is saved to the XPS file. I tried wrapping SaveFlowDocumentToXpsFile in a call to Dispatcher.BeginInvoke but it did not help.

My questions are:

  1. Can I somehow force the images to load before saving the XPS file without actually showing the document on screen? (I tried fiddling with BitmapImage.CreateOptions with no luck).
  2. If there is no solution to question #1, is there a way to tell when FlowDocumentPageViewer has finished loading its contents so that I know when it is save to create the XPS file?
like image 213
Jakob Christensen Avatar asked Mar 11 '10 13:03

Jakob Christensen


People also ask

Is XPS an image file?

An XPS file is a document that contains fixed page layout information written in the XPS page description language. The file defines a document's layout, appearance, and printing information. XPS files are similar to . PDF files, but saved in Microsoft's proprietary XPS format.

Where are XPS files saved?

Windows will save . xps files in your Documents folder by default. If you would like to attach a digital signature to an XPS document before you send or share it, you can do so.

What is XPS file viewer?

XPS files or XML Paper Specification files are Microsoft's direct competitor to Adobe's PDF format. XPS Viewer is a tool used to view XPS files, similar to Adobe Reader. While XPS might not be as popular as PDF, some Windows users still work with it.


1 Answers

The eventual solution was the same as you came to, which is to put the document in a viewer and briefly show it on screen. Below is the helper method that I wrote to do this for me.

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();
    }
}

Edit: I just added window.ShowInTaskbar = false to the method as if you were quick you could see the window appear in the taskbar.

The user will never "see" the window as it is positioned way off-screen at Int32.MaxValue - a trick that was common back in the day with early multimedia authoring (e.g. Macromedia/Adobe Director).

For people searching and finding this question, I can tell you that there is no other way to force the document to render.

HTH,

like image 169
Dennis Avatar answered Sep 16 '22 18:09

Dennis