0

I have found a strange behaviour while trying to print a FlowDocument which is stored inside the .xaml file. Let me show you how this works. We have a simple ViewModel-like class:

public class FooViewModel
{
    public FlowDocument Fd { get; set; }

    public FooViewModel()
    {
        this.Fd = Application.LoadComponent(new Uri("/someassembly;component/somepath.xaml", UriKind.Relative)) as FlowDocument;
    }

    public void Print()
    {
        PrintDialog pd new PrintDialog();
        pd.PrintQueue = new PrintQueue(new LocalPrintServer(), "Canon MP280 series");

        FlowDocument document = this.Fd;
        document.DataContext = new LabelTicket(); //stores data for printing
        DocumentPaginator dp = ((IDocumentPaginatorSource)document).DocumentPaginator;
        pd.PrintDocument(dp, "someTitle");
    }
} 

This code works, printing job is started and the physical printer is doing it's job. But when we change one line in Print() method to:

FlowDocument document = Application.LoadComponent(new Uri("/someassembly;component/somepath.xaml", UriKind.Relative)) as FlowDocument;

Something strange starts to happen. Delaying the component loading to actual printing makes printing impossible. The printing job appears in the Windows Printing Queue of this particular printer, but it disappears almost immediately. Turning on the Windows Event Tracking for printing shows that: "Win32 error code returned by the print processor: 63 (0x3f)." Changing the printer to any other physical printer gives the same effect.

On the other hand changing printer to any non-physical printer like "Microsoft XPS Document Writer" performs this printing without problem.

I've also tried loading the FlowDocument from ResourceDictionary but with the same effect. Could someone give me a hint how to solve this problem?

Mateusz Myślak
  • 775
  • 6
  • 16

1 Answers1

0

The not so obvious answer might be that you need to "display" the FlowDocument so that it knows how to render in some type of way. With a virtual printer like the XPS Doc Writer, it probably knows how to render a FlowDocument properly. On printers that don't have XPS drivers installed, it may not know how to render properly.

Your best bet is probably to "silently" render the FlowDocument before you send it off to the printer. Also, this probably isn't a pure MVVM view model, because your view model probably shouldn't have reference to FlowDocument and even PrintDialog.

Anyways, you could try doing something like this to silently render:

public void Print()
{
    PrintDialog pd = new PrintDialog();
    if(pd.ShowDialog() == true) //allow user to pick printer and preferences if they choose to do so
    {

        FlowDocument document = Application.LoadComponent(new Uri("/someassembly;component/somepath.xaml", UriKind.Relative)) as FlowDocument;

        document.DataContext = new LabelTicket(); //stores data for printing

        Grid g = new Grid();
        ContentPresenter cp = new ContentPresenter();
        cp.Content = document;
        g.Children.Add(cp);
        var _printableAreaSize = new Size(pd.PrintableAreaWidth, pd.PrintableAreaHeight);
        g.Measure(_printableAreaSize);
        g.Arrange(new Rect(new Point(), _printableAreaSize));
        g.UpdateLayout();

        DocumentPaginator dp = ((IDocumentPaginatorSource)document).DocumentPaginator;

        pd.PrintDocument(dp, "someTitle");
    }
}

As you step through the Measure/Arrange/UpdateLayout calls, you should see the Grids height/width change because it is rendering without actually being displayed.

Kcvin
  • 5,073
  • 2
  • 32
  • 54
  • If you don't want to show a print dialog, then you should use `LocalPrintServer.GetDefaultPrintQueue()` or something that will give you the dimensions/size you can print so you can specify the correct dimensions before creating the paginator. – Kcvin Mar 07 '16 at 22:35
  • For the designing and debugging purposes I've used the VM as a bind source for the view. But when it came to testing, I've removed the FlowDocument from the View. Now, the VM is being initialized during View creation (as a static resource) an then the FlowDocument works, but when I move this to any different part of application it is basically dead. Of course, you are also right it should be displayed to make it work, but why the constructor makes this possible? Currently, I've redesigned the FlowDocument so it is using only tables and paragraphs, and now it works anywhere without displaying. – Mateusz Myślak Mar 08 '16 at 11:01