为什么我在打印到XpsDocument时丢失了数据绑定?

时间:2021-01-03 22:34:03

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.

绑定工作。问题是XpsDocumentWriter没有正确写入FixedDocumentSequence的第一个文档的第一页。这似乎是很多人在做这类事情时遇到的问题(即全世界有五个开发人员)。解决方案有点奇怪。我把它作为答案包括在内。


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.

我有一系列的FixedPages,每个都有单独的DataContext设置。每个FixedPage还有一个或多个绑定到上下文的控件。

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.

如果我将这些FixedPages添加到单个FixedDocument并将此单个FixedDocument写入XpsDocument,我的绑定将被取消引用(可以这么说),并且正确的值将显示在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.

如果我将这些FixedPages添加到单个FixedDocuments(每个FP被添加到一个新的FD),那么这些FixedDocuments被添加到FixedDocumentSequence,然后这个序列被写入XpsDocument,我的绑定没有被引用,我的FixedPages显示为空白。

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!

显然,当我的固定文档没有被写入Xps文档时,无论发生什么样的魔法导致数据绑定被评估并且插入绑定值都不会发生。我需要能够编写多个固定文档,而Write方法只能调用一次,因此需要将FixedDocuments添加到FixedDocumentSequence中然后编写。但是我也需要我该死的数据绑定工作!

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).

在这种情况下的任何帮助将不胜感激。我知道它不完全是框架中最常见的部分;我只是希望有人在这里有一些操作经验(我在看着你,潜伏着MS员工)。

3 个解决方案

#1


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.

这个错误的原因是在写入之前没有更新FixedPage的布局。这会导致FixedDocumentSequence中第一个FixedDocument中的第一个FixedPage被错误地写入。这会影响结果文档中的其他页面,这使得此错误/边缘情况更难确定。

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

以下WORKS(非工作示例的重写版本):

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

#2


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

我在尝试使用XpsDocumentWriter写入PrintQueue时发现了这个问题。以下代码正确打印第一页。

//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.

如果删除printDialog.ShowDialog()并尝试静默打印到默认打印机,则第一页打印不正确。但是,在我的场景中,我不需要使用FixedDocumentSequence,所以我将它换成了一个FixedDocument并且静默打印工作。我尝试更新FixedPage上的布局但没有成功。如果我显示打印对话框,第一页打印正常会很奇怪。

#3


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.

丢失绑定的一个原因是你在某个地方抛出一个异常 - 不幸的是,这个异常被静默吞噬,你的绑定只是“停止工作”。启用第一次机会异常并查看是否有任何问题。

#1


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.

这个错误的原因是在写入之前没有更新FixedPage的布局。这会导致FixedDocumentSequence中第一个FixedDocument中的第一个FixedPage被错误地写入。这会影响结果文档中的其他页面,这使得此错误/边缘情况更难确定。

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

以下WORKS(非工作示例的重写版本):

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

#2


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

我在尝试使用XpsDocumentWriter写入PrintQueue时发现了这个问题。以下代码正确打印第一页。

//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.

如果删除printDialog.ShowDialog()并尝试静默打印到默认打印机,则第一页打印不正确。但是,在我的场景中,我不需要使用FixedDocumentSequence,所以我将它换成了一个FixedDocument并且静默打印工作。我尝试更新FixedPage上的布局但没有成功。如果我显示打印对话框,第一页打印正常会很奇怪。

#3


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.

丢失绑定的一个原因是你在某个地方抛出一个异常 - 不幸的是,这个异常被静默吞噬,你的绑定只是“停止工作”。启用第一次机会异常并查看是否有任何问题。