基于事件的 XPS 页面修改 | .NET
什么是基于事件的编程方法?
基于事件的编程方法是一种围绕事件和事件处理概念的范式。在此模型中,程序的流程由事件决定,这些事件可以是用户操作(例如鼠标点击或键盘按下)、系统生成的通知或来自其他应用程序的消息。以下是基于事件的方法的一些关键方面:
事件:事件表示程序中发生的重大事件。这些事件可以包括用户交互、数据更改或来自系统其他部分的消息。例如,按钮点击或文件加载都可能触发事件。
事件监听器:为了响应事件,程序员使用事件监听器(或事件处理程序)。这些是定义为在特定事件发生时执行的函数或方法。例如,可以设置事件监听器以在用户点击按钮时执行某个函数。
异步执行:基于事件的模型通常支持异步编程,允许程序在等待事件发生时保持响应。例如,Web 应用程序可以在等待服务器数据的同时继续运行。
解耦:基于事件的方法促进了程序不同部分之间的解耦。组件可以通过事件进行通信,而无需了解彼此的实现细节,从而使代码更加模块化且更易于维护。
常见用例:事件驱动编程广泛应用于图形用户界面 (GUI)、Web 应用程序以及需要实时交互的系统中。Node.js、React 等许多框架和库都使用了事件驱动模式。
状态管理:在事件驱动系统中,状态管理至关重要,因为应用程序可能会根据用户交互或事件处于不同的状态。通常采用适当的状态管理策略来确保应用程序按预期运行。
总的来说,基于事件的方法是管理程序内交互和工作流的有效方法,对于需要响应能力和用户交互的应用程序特别有效。
XPS 文档转换期间发生的事件
当您需要使用 Aspose.Page API 更改 XPS 文档的特定页面时,通常需要选择活动文档(如果 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 或图像时,该过程会逐页进行。当转换作业准备好处理下一页时,它会触发“before-page”事件。用户可以通过扩展 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 的页面。因此,构造函数应该将 options 的数组属性作为参数。如果指定了页码数组,我们会创建一个已排序的页码集合,同时避免重复。(顺便说一句,这个解决方案并不完全准确。你能找出导致输出不一致的原因吗?)我们还需要一个 XpsFont
对象,其中包含超链接文本的字体数据。
所有操作都发生在重写的 Handle()
方法中。该方法的参数是一个对象,其中包含当前页面的修改 API、XPS 包中的文档编号、所有文档的 绝对页码、当前文档中的 相对页码(如果包中只有一个文档,则等于之前的页码)以及 输出页码(当我们转换整个包时,它等于绝对页码)。
以下两个 if
块的逻辑非常简单。它基于对 OutputPageNumber
事件参数的分析,在适当的情况下省略了一些链接:[First]
和 [Prev]
链接将添加到除第一个页面之外的所有输出页面,而 [Next]
和 [Last]
链接将出现在除最后一个页面之外的所有页面上。无论是否指定页码,该逻辑都针对这两种情况进行了定制。
if
块之后是用于在页面右下角添加页码的代码。
最后一行添加了页面的大纲条目,该条目将显示在 PDF 查看器的导航窗格中(如果支持)。
转换代码
既然已经定义了“before-page”事件处理程序,我们就可以编写转换文档的代码了:
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
类的实例,并指定需要转换的页数。下一行代码中,“before-page”事件处理程序通过 BeforePageSavingEventHandlers
集合选项与转换任务“连接”。
接下来只需使用文档的 SaveAsPdf()
方法将文件转换为 PDF 格式即可。
结论
在本文中,我们探讨了基于事件的编程方法的关键点,研究了直接修改 XPS 文档页面的方法,并学习了一种更高级、更复杂的技术,用于在转换过程中对所有输出页面进行重复更改,并以插入导航超链接为例。
如需查看完整示例,请探索我们的 示例项目。