Я создаю файлы 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.Я что-то упускаю?