Изменения страницы XPS на основе событий | .NET
Что такое событийный подход в программировании?
Событийный подход в программировании — это парадигма, которая вращается вокруг концепции событий и их обработки. В этой модели ход выполнения программы определяется событиями, которыми могут быть действия пользователя (например, щелчки мыши или нажатия клавиш), генерируемые системой уведомления или сообщения от других приложений. Вот некоторые ключевые аспекты событийно-ориентированного подхода:
События: События представляют собой важные события в программе. Они могут включать взаимодействие с пользователем, изменения в данных или сообщения из других частей системы. Например, нажатие кнопки или загрузка файла могут вызвать события.
Прослушиватели событий. Чтобы реагировать на события, программисты используют прослушиватели событий (или обработчики). Это функции или методы, которые определены для выполнения при возникновении определенного события. Например, прослушиватель событий можно настроить на выполнение функции, когда пользователь нажимает кнопку.
Асинхронное выполнение. Модель, основанная на событиях, часто поддерживает асинхронное программирование, позволяя программам оставаться отзывчивыми в ожидании возникновения событий. Например, веб-приложение может продолжать работать, ожидая данных с сервера.
Развязка. Подход, основанный на событиях, способствует разделению различных частей программы. Компоненты могут взаимодействовать посредством событий, не зная деталей реализации друг друга, что делает код более модульным и простым в обслуживании.
Распространенные случаи использования. Программирование, управляемое событиями, широко используется в графических интерфейсах пользователя (GUI), веб-приложениях и системах, требующих взаимодействия в реальном времени. Фреймворки и библиотеки, такие как Node.js, React и многие другие, используют шаблоны, управляемые событиями.
Управление состоянием. В системе, управляемой событиями, управление состоянием может иметь решающее значение, поскольку приложение может находиться в разных состояниях в зависимости от действий пользователя или событий. Правильные стратегии управления состоянием часто используются для обеспечения ожидаемого поведения приложения.
В целом, подход на основе событий — это мощный способ управления взаимодействиями и рабочими процессами внутри программы, что делает его особенно эффективным для приложений, требующих оперативности и взаимодействия с пользователем.
События, происходящие во время преобразования документа XPS
Когда вам нужно внести изменения в определенную страницу документа XPS с помощью API Aspose.Page, вы обычно выбираете активный документ (если в файле XPS несколько документов), выбираете активную страницу, а затем сами вносите изменения. .
Теперь предположим, что вам нужно внести повторяющиеся изменения во все страницы файла XPS, а затем преобразовать результат в PDF или формат изображения. Некоторые примеры таких изменений включают размещение водяных знаков на страницах или добавление навигационных гиперссылок. Прямой способ внесения таких изменений включает в себя просмотр документов в пакете XPS, просмотр страниц текущего активного документа и, наконец, применение ваших изменений. Таким образом, код для выполнения этой задачи будет выглядеть следующим образом:
1for (int i = 1; i <= document.DocumentCount; i++)
2{
3 document.SelectActiveDocument(i);
4 for (j = 1; j <= document.PageCount; j++)
5 {
6 document.SelectActivePage(j);
7 // Your changes ...
8 }
9}
10document.SaveAsPdf("file-name.pdf", saveOptions);
Если вам также необходимо внести некоторые нерегулярные изменения перед повторяющимися, этот подход может привести к некоторой путанице или чрезмерному обходу документов и страниц, не говоря уже о том, что эти циклы могут показаться немного громоздкими. Когда вы конвертируете документ XPS в PDF или изображение, процесс происходит страница за страницей. Когда задание преобразования готово к обработке следующей страницы, оно вызывает событие «до страницы». Пользователь может определить обработку таких событий, расширив класс BeforePageSavingEventHandler, тем самым воспользовавшись некоторыми преимуществами, описанными во вводном разделе этой статьи.
Пример добавления навигационных гиперссылок
Здесь мы приведем пример, связанный с навигационными гиперссылками. А чтобы немного усложнить задачу, мы преобразуем в PDF только часть всех страниц, как указано в свойстве PdfSaveOptions.PageNumbers.
Класс обработчика событий
Ниже показано расширение класса BeforePageSavingEventHandler:
1/// <summary>
2/// The class to handle the before-page event while converting an XPS document.
3/// </summary>
4public class NavigationInjector : BeforePageSavingEventHandler
5{
6 // The font in which navigation hyperlinks and page numbers will be displayed.
7 private readonly XpsFont _font;
8 // The page numbers to convert.
9 private readonly SortedList<int, int> _pageNumbers;
10
11 public NavigationInjector(XpsFont font, int[] pageNumbers)
12 {
13 _font = font;
14 if (pageNumbers == null)
15 return;
16
17 // Turn the page number array into a sorted collection of unique values.
18 _pageNumbers = new SortedList<int, int>();
19 foreach (int pn in pageNumbers)
20 _pageNumbers[pn] = 0;
21 }
22
23 public override void Handle(BeforeSavingEventArgs<PageAPI> args)
24 {
25 PageAPI api = args.ElementAPI;
26
27 XpsGlyphs glyphs;
28 // For all pages in the output PDF except the first one...
29 if (args.OutputPageNumber > 1)
30 {
31 // ...insert a hyperlink to the first page...
32 glyphs = api.CreateGlyphs(_font, 15f, 5f, api.Height - 10f, "[First]");
33 glyphs.Fill = api.CreateSolidColorBrush(Color.Blue);
34 glyphs.HyperlinkTarget = new XpsPageLinkTarget(_pageNumbers == null ? 1 : _pageNumbers.Keys[0]);
35 api.Add(glyphs);
36
37 // ...and to the previous page.
38 glyphs = api.CreateGlyphs(_font, 15f, 60f, api.Height - 10f, "[Prev]");
39 glyphs.Fill = api.CreateSolidColorBrush(Color.Blue);
40 glyphs.HyperlinkTarget = new XpsPageLinkTarget(
41 _pageNumbers == null ? args.AbsolutePageNumber - 1 : _pageNumbers.Keys[args.OutputPageNumber - 2]);
42 api.Add(glyphs);
43 }
44
45 // For all pages in the output PDF except the last one...
46 if ((_pageNumbers != null && args.OutputPageNumber < _pageNumbers.Count) ||
47 (_pageNumbers == null && args.OutputPageNumber < api.TotalPageCount))
48 {
49 // ...insert a hyperlink to the next page...
50 glyphs = api.CreateGlyphs(_font, 15f, 110f, api.Height - 10f, "[Next]");
51 glyphs.Fill = api.CreateSolidColorBrush(Color.Blue);
52 glyphs.HyperlinkTarget = new XpsPageLinkTarget(
53 _pageNumbers == null ? args.AbsolutePageNumber + 1 : _pageNumbers.Keys[args.OutputPageNumber]);
54 api.Add(glyphs);
55
56 // ...and to the last page.
57 glyphs = api.CreateGlyphs(_font, 15f, 160f, api.Height - 10f, "[Last]");
58 glyphs.Fill = api.CreateSolidColorBrush(Color.Blue);
59 glyphs.HyperlinkTarget = new XpsPageLinkTarget(
60 _pageNumbers == null ? api.TotalPageCount : _pageNumbers.Keys[_pageNumbers.Keys.Count - 1]);
61 api.Add(glyphs);
62 }
63
64 // Insert a page number in the bottom-right corner.
65 glyphs = api.CreateGlyphs(_font, 15f, api.Width - 20f, api.Height - 10f, args.OutputPageNumber.ToString());
66 glyphs.Fill = api.CreateSolidColorBrush(Color.Black);
67 api.Add(glyphs);
68
69 // Add an outline entry to display the links to the converted pages in the navigation pane of a PDF viewer.
70 api.AddOutlineEntry(string.Format("Page {0}", args.OutputPageNumber), 1, args.AbsolutePageNumber);
71 }
72}
Класс-обработчик должен знать, какие страницы мы хотим сохранить в формате PDF, чтобы создать правильные цели гиперссылок. Следовательно, конструктор должен принимать в качестве аргумента свойство массива параметров. Если указан массив номеров страниц, мы создаем их отсортированную коллекцию, избегая при этом дубликатов. (Кстати, это решение не совсем точное. Можете ли вы выяснить, что может вызвать несогласованность вывода?) Нам также понадобится объект XpsFont, содержащий данные шрифта для текста гиперссылки.
Все это происходит в переопределенном методе Handle(). Аргументом метода является объект, который содержит API модификации для текущей страницы, номер документа в пакете XPS, абсолютный номер страницы во всех документах, относительный номер страницы в текущем документе (который равен предыдущий номер, если в пакете только один документ) и номер выходной страницы (который равен абсолютному номеру страницы при конвертации всего пакета).
Логика следующих двух блоков if довольно проста. Он основан на анализе аргумента события OutputPageNumber
для исключения некоторых ссылок, где это необходимо: ссылки [First]
и [Prev]
будут добавлены ко всем выходным страницам, кроме первой, а Ссылки [Следующий]
и [Последний]
появятся на всех страницах, кроме последней. Логика также адаптирована для обоих случаев, независимо от того, указаны номера страниц или нет.
После блоков if в правом нижнем углу страницы находится код для добавления номера страницы.
Последняя строка добавляет запись структуры страницы, элемент, который будет отображаться в панели навигации средства просмотра PDF (если поддерживается).
Код преобразования
Теперь, когда обработчик события «перед страницей» определен, мы можем написать код, преобразующий документ:
1// The path to the documents directory.
2string dataDir = RunExamples.GetDataDir_WorkingWithPages();
3// Open an XPS document
4using (XpsDocument doc = new XpsDocument(dataDir + "Sample3.xps"))
5// Create a font
6using (Stream fontStream = File.OpenRead(dataDir + "arialbd.ttf"))
7{
8 // Create options for conversion to PDF
9 PdfSaveOptions options = new PdfSaveOptions();
10 // Set the filter for the pages that need conversion
11 options.PageNumbers = new int[] { 2, 6, 7, 13 };
12 // Add the event handler that will execute right before the conversion of each page
13 options.BeforePageSavingEventHandlers.Add(new NavigationInjector(doc.CreateFont(fontStream), options.PageNumbers));
14 // Save resultant XPS document
15 doc.SaveAsPdf(dataDir + "ModifyPageOnConversion_out.pdf", options);
16}
Мы открываем файл XPS, а затем создаем экземпляр объекта потока с файлом данных шрифта. Далее мы создаем экземпляр класса PdfSaveOptions и указываем количество страниц, которые нам нужно преобразовать. В следующей строке обработчик событий «до страницы» «подключается» к заданию преобразования через опцию сбора «BeforePageSavingEventHandlers».
Все, что осталось сделать, это запустить преобразование в PDF, используя метод SaveAsPdf() документа.
Заключение
В этой статье мы рассмотрели ключевые моменты событийно-ориентированного подхода в программировании, рассмотрели прямой метод изменения страниц документа XPS и изучили более продвинутый и сложный метод внесения повторяющихся изменений во все выходные страницы во время процесс преобразования на примере вставки навигационных гиперссылок.
Полные примеры можно найти в нашем Пример проекта.