Why am I losing my databinding when printing to an XpsDocument?
Asked Answered
U

3

8

Update!

Binding works. The issue is that the XpsDocumentWriter doesn't properly write the first page of the first document of a FixedDocumentSequence. This seems to be an issue encountered by lots of people doing this sort of thing (i.e., five developers worldwide). The solution is slightly odd. I include it as an answer.


Okay, its a bit more subtle than the question suggests.

I've got a series of FixedPages, each has its DataContext set individually. Each FixedPage also has one or more controls that are bound to the context.

If I add these FixedPages to a single FixedDocument and write this single FixedDocument to an XpsDocument, my binds are de-referenced (so to speak) and the correct values are presented in the XpsDocument.

If I add these FixedPages to individual FixedDocuments (each FP gets added to a new FD), then these FixedDocuments are added to a FixedDocumentSequence, and this sequence is then written to the XpsDocument, my binds are NOT de-referenced and my FixedPages appear blank.

Debugging tells me that I'm not losing my bindings or my binding context, so that's not the cause of this failure.

Here's some sample code to illustrate what's going on:

// This works
FixedPage fp = CreateFixedPageWithBinding();
fp.DataContext = CreateDataContext();
// Add my databound fixed page to a new fixed document
var fd = new FixedDocument();
var pc = new PageContent();
((IAddChild)pc).AddChild(fp);
fd.Pages.Add(pageContent);
// Create an xps document and write my fixed document to it
var p = Package.Open("c:\\output.xps", FileMode.CreateNew);
var doc = new XpsDocument(p);
var writer = XpsDocument.CreateXpsDocumentWriter(doc);
wri2.Write(fd);
p.Flush();
p.Close();

// This does NOT work
FixedPage fp = CreateFixedPageWithBinding();
fp.DataContext = CreateDataContext();
// Add my databound fixed page to a new fixed document
var fd = new FixedDocument();
var pc = new PageContent();
((IAddChild)pc).AddChild(fp);
fd.Pages.Add(pageContent);
// Create a fixed document sequence and add the fixed document to it
FixedDocumentSequence fds = CreateFixedDocumentSequence();
var dr = new DocumentReference();
dr.BeginInit();
dr.SetDocument(fd);
dr.EndInit();
(fds as IAddChild).AddChild(dr);
// Create an xps document and write the fixed document sequence to it
var p = Package.Open("c:\\output.xps", FileMode.CreateNew);
var doc = new XpsDocument(p);
var writer = XpsDocument.CreateXpsDocumentWriter(doc);
wri2.Write(fds);
p.Flush();
p.Close();

You can see that the only difference between the two is that I'm adding the fixed document to a fixed document sequence, which then gets written.

Obviously, whatever magic happens that causes the databinding to be evaluated and the bound values be inserted isn't happening when my fixed documents aren't being Written to the Xps Document. I need to be able to write more than one fixed document, and the Write method can only be called once, thus requiring I add the FixedDocuments to a FixedDocumentSequence which I then write. But I also need my damn databinding to work as well!

Any help in this situation would be appreciated. I know its not exactly the most common part of the framework; I'm just hoping that someone here has some operational experience with this (I'm looking at you, lurking MS employee).

Ungrudging answered 15/1, 2009 at 23:54 Comment(0)
U
9

The cause of this bug is that the FixedPage's layout isn't being updated prior to writing. This causes the first FixedPage in the first FixedDocument in the FixedDocumentSequence to be written incorrectly. This affects NO OTHER PAGES IN THE RESULTING DOCUMENT, which made this bug/edge case harder to nail down.

The following WORKS (rewritten version of the non-working example):

FixedPage fp = CreateFixedPageWithBinding();
fp.DataContext = CreateDataContext();
var fd = new FixedDocument();

/* PAY ATTENTION HERE */
// set the page size on our fixed document 
fd.DocumentPaginator.PageSize =
   new System.Windows.Size()
   {
       Width = DotsPerInch * PageWidth,
       Height = DotsPerInch * PageHeight
   };
// Update the layout of our FixedPage
var size = fd.DocumentPaginator.PageSize;
page.Measure(size);
page.Arrange(new Rect(new Point(), size));
page.UpdateLayout();    
/* STOP PAYING ATTENTION HERE */

var pc = new PageContent();
((IAddChild)pc).AddChild(fp);
fd.Pages.Add(pageContent);
// Create a fixed document sequence and add the fixed document to it
FixedDocumentSequence fds = CreateFixedDocumentSequence();
var dr = new DocumentReference();
dr.BeginInit();
dr.SetDocument(fd);
dr.EndInit();
(fds as IAddChild).AddChild(dr);
// Create an xps document and write the fixed document sequence to it
var p = Package.Open("c:\\output.xps", FileMode.CreateNew);
var doc = new XpsDocument(p);
var writer = XpsDocument.CreateXpsDocumentWriter(doc);
wri2.Write(fds);
p.Flush();
p.Close();
Ungrudging answered 16/1, 2009 at 16:51 Comment(6)
There might be additional stuff going on in the background, but this part of the framework is not well documented or widely used, so I might be missing details/side effects/causes/effects.Ungrudging
Note to searchers--another interesting fact I learned recently is that if you're using the SerializerWriterCollator to write visuals to an XpsDocumentWriter (call CreateVisualsCollator on the writer to get it), you can re-use your visual after each write. Saves the day when you've got thousands and thousands of visuals to write.Ungrudging
Also, for each visual, you must call Measure and Arrange at least once. After that, you can update bindings by calling UpdateLayout after changing the DataContextUngrudging
Up-vote the bug report here.Therese
@JVimes you should link the report to hereUngrudging
I have it under "details". The edit feature seems broke, so I can't add it to the summary, or add the Workaround. :/Therese
P
1

I found this issue while trying to use XpsDocumentWriter to write to a PrintQueue. The following code prints the first page correctly.

//Prints correctly
FixedDocumentSequence Documents = new FixedDocumentSequence();

//some code to add DocumentReferences to FixedDocumentSequence

PrintDialog printDialog = new PrintDialog
{
    PrintQueue = LocalPrintServer.GetDefaultPrintQueue() 
};
printDialog.PrintTicket = printDialog.PrintQueue.DefaultPrintTicket;
if (printDialog.ShowDialog() == true)
{
    Documents.PrintTicket = printDialog.PrintTicket;

    XpsDocumentWriter writer = PrintQueue.CreateXpsDocumentWriter(printDialog.PrintQueue);
    writer.Write(Documents, printDialog.PrintTicket);
    printerName = printDialog.PrintQueue.FullName;
}

If you remove the printDialog.ShowDialog() and just attempt to silent print to the default printer, the first page prints incorrectly. However, in my scenario, I didn't need to use a FixedDocumentSequence so I swapped it out for just a single FixedDocument and silent printing worked. I tried updating the layout on the FixedPage without success. Weird how the first page prints fine if I show the print dialog though.

Prosenchyma answered 28/11, 2017 at 22:48 Comment(1)
FixedDocument seems like the keyShantay
S
0

One reason that you lose a binding is that you throw an exception somewhere - unfortunately, this exception is silently swallowed and your binding just "stops working". Turn on First-chance exceptions and see if anything gets hit.

Stoical answered 16/1, 2009 at 3:5 Comment(1)
This process is full of potholes and I've seen many exceptions when trying to do this another way. Exceptions are only swallowed during the binding, and I know that works (I can write he document successfully and then immediately add it to a sequence and write that, which fails).Ungrudging

© 2022 - 2024 — McMap. All rights reserved.