首页 > 解决方案 > 创建具有多种页面大小的 XPS 文档

问题描述

我正在从 XAML 元素创建 XPS 文件。不仅如此,我正在创建 XPS 文件,其中每个页面的大小可能不同。看到这个最小的复制:

using (Package pkg = Package.Open("out.xps", FileMode.Create))
using (XpsDocument doc = new XpsDocument(pkg))
{
    XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc);
    SerializerWriterCollator collator = writer.CreateVisualsCollator();

    WritePage(816, 1344); // 8.5 x 14
    WritePage(816, 1056); // 8.5 x 11
    WritePage(816, 1344);
    WritePage(816, 1056);

    collator.EndBatchWrite();

    doc.Close();
    pkg.Close();

    void WritePage(double width, double height)
    {
        var element = new Border()
        {
            Width = width,
            Height = height,
            BorderBrush = Brushes.Black,
            BorderThickness = new Thickness(10.0)
        };

        Size size = new Size(width, height);
        element.Measure(size);
        element.Arrange(new Rect(size));
        element.UpdateLayout();

        collator.Write(element);
    }
}

我遇到的问题是我所有的页面最终都是相同的大小。或者更准确地说,与第一页大小相同。该文档的页面均显示为:

<FixedPage ... Width="816" Height="1344">

我第一次尝试解决这个问题是PrintTicket在我写的时候设置一个 - 但它没有效果。

稍后进行一些调试,我将问题追溯到 WPF 方法XpsSerializationManager.SaveAsXml

if (this._simulator == null)
{
    this._simulator = new ReachHierarchySimulator(
        (PackageSerializationManager) this, serializedObject);
}

...

if (this._isBatchMode)
{
    xmlWriter = this._simulator.SimulateBeginFixedPage();
}

在这里,它_simulator仅在第一次调用时进行初始化SaveAsXml。存储在模拟器中的是serializedObject——Visual我们试图保存的。问题是,这个参考在后续调用中仍然存在。

接下来,它调用_simulator.SimulateBeginFixedPage创建第一个<FixedPage>元素——但因为它引用了原始对象,所以每个页面的大小都与该对象相同。

所以我所做的解决方法是在每次Write调用之前通过反射更新该引用:

void WritePage(double width, double height)
{
    var element = new Border()
    {
        Width = width,
        Height = height,
        BorderBrush = Brushes.Black,
        BorderThickness = new Thickness(10.0),
        Tag = pageCounter++
    };

    object manager = collator.GetType()
        .GetField("_manager", BindingFlags.Instance | BindingFlags.NonPublic)
        ?.GetValue(collator);

    object simulator = manager?.GetType()
        .GetField("_simulator", BindingFlags.Instance | BindingFlags.NonPublic)
        ?.GetValue(manager);

    simulator?.GetType()
        .GetField("_serializedObject", BindingFlags.Instance | BindingFlags.NonPublic)
        .SetValue(simulator, element);

    Size size = new Size(width, height);
    element.Measure(size);
    element.Arrange(new Rect(size));
    element.UpdateLayout();

    collator.Write(element);
}

但是——我觉得这太奇怪了,可能是我使用 WPF 的问题,而不是 WPF 本身的错误。有什么我想念的吗?

标签: .netwpfxps

解决方案


推荐阅读