Создание документов XPS с несколькими размерами страниц - PullRequest
0 голосов
/ 24 октября 2018

Я создаю файлы XPS из элементов XAML.Более того, я создаю 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.Я что-то упускаю?

...