自定义 SDK 功能
Open XML SDK 中的功能从 v2.14.0 开始提供,它允许行为和状态包含在文档或部件中,并且无需重新实现包含的包或部件即可进行自定义。 可通过包、部件和元素上的 属性访问 Features
。
这是 策略模式 的实现,可以轻松地动态替换行为。 它按照 ASP.NET Core 中的请求功能建模。
特征继承
包、部件和元素都有其自己的功能集合。 但是,他们还将继承包含部件和包(如果可用)。
若要突出显示这一点,请参阅下面的测试用例:
OpenXmlPackage package = /* Create a package */;
var packageFeature = new PrivateFeature();
package.Features.Set<PrivateFeature>(packageFeature);
var part = package.GetPartById("existingPart");
Assert.Same(part.Features.GetRequired<PrivateFeature>(), package.Features.GetRequired<PrivateFeature>());
part.Features.Set<PrivateFeature>(new());
Assert.NotSame(part.Features.GetRequired<PrivateFeature>(), package.Features.GetRequired<PrivateFeature>());
private sealed class PrivateFeature
{
}
注意
元素的特征集合是只读的。 这是由于内存问题(如果它是可写的)。 如果需要,请继续联系 https://github.com/dotnet/open-xml-sdk ,告知我们你的方案。
可视化已注册的功能
的内置实现 IFeatureCollection
提供了一个有用的调试视图,以便你可以查看哪些功能可用及其属性/字段:
可用功能
下面介绍了当前可用的功能及其可用的范围:
IDisposableFeature
此功能允许注册在包或部件被销毁或释放时需要运行的操作:
OpenXmlPackage package = GetSomePackage();
package.Features.Get<IDisposableFeature>().Register(() => /* Some action that is called when the package is disposed */);
OpenXmlPart part = GetSomePart();
part.Features.Get<IDisposableFeature>().Register(() => /* Some action that is called when the part is removed or closed */);
包和部件将具有其自己的此功能实现。 元素将检索其包含部件的功能(如果可用)。
IPackageEventsFeature
此功能允许获取包更改时的事件通知:
OpenXmlPackage package = GetSomePackage();
package.TryAddPackageEventsFeature();
var feature = package.Features.GetRequired<IPackageEventsFeature>();
注意
有时包已更改,但未触发事件。 并非所有领域都已确定在哪些方面都有意义地提出事件。 如果找到问题,请提交问题。
IPartEventsFeature
此功能允许获取创建事件时的事件通知。 这是添加到部件或包的功能:
OpenXmlPart part = GetSomePackage();
package.AddPartEventsFeature();
var feature = part.Features.GetRequired<IPartEventsFeature>();
通常,假设事件可能有单一实例实现,并验证部件是否正确。
注意
有时,部件已更改,但未触发事件。 并非所有领域都已确定在哪些方面都有意义地提出事件。 如果找到问题,请提交问题。
IPartRootEventsFeature
此功能允许在修改/加载/创建/等部件根目录时获取事件通知。这是添加到部件级别功能的功能:
OpenXmlPart part = GetSomePart();
part.AddPartRootEventsFeature();
var feature = part.Features.GetRequired<IPartRootEventsFeature>();
通常,假设事件可能有单一实例实现,并验证部件是否正确。
注意
有时,部件根已更改,但未触发事件。 并非所有领域都已确定在哪些方面都有意义地提出事件。 如果找到问题,请提交问题。
IRandomNumberGeneratorFeature
此功能允许共享服务生成随机数并填充数组。
IParagraphIdGeneratorFeature
此功能允许填充和跟踪包含段落 ID 的元素。 默认情况下,这将确保值的唯一性,并确保确实存在的值根据标准的约束有效。 若要使用此功能,请执行以下操作:
WordprocessingDocument document = CreateWordDocument();
document.TryAddParagraphIdFeature();
var part = doc.AddMainDocumentPart();
var body = new Body();
part.Document = new Document(body);
var p = new Paragraph();
body.AddChild(p); // After adding p.ParagraphId will be set to a unique, valid value
此功能还可用于确保多个文档的唯一性,但略有更改:
using var doc1 = CreateDocument1();
using var doc2 = CreateDocument2();
var shared = doc1
.AddSharedParagraphIdFeature()
.Add(doc2);
// Add item to doc1
var part1 = doc1.AddMainDocumentPart();
var body1 = new Body();
var p1 = new Paragraph();
part1.Document = new Document(body1);
body1.AddChild(p1);
// Add item with same ID to doc2
var part2 = doc2.AddMainDocumentPart();
var body2 = new Body();
var p2 = new Paragraph { ParagraphId = p1.ParagraphId };
part2.Document = new Document(body2);
body2.AddChild(p2);
// Assert
Assert.NotEqual(p1.ParagraphId, p2.ParagraphId);
Assert.Equal(2, shared.Count);
IPartRootXElementFeature
此功能允许 OpenXmlPart
通过使用 XLinq 功能和直接操作 XElement
节点来操作 。
OpenXmlPart part = GetSomePart();
var node = new(W.document, new XAttribute(XNamespace.Xmlns + "w", W.w),
new XElement(W.body,
new XElement(W.p,
new XElement(W.r,
new XElement(W.t, "Hello World!")))));
part.SetXElement(node);
这会 XElement
缓存,但如果要更改,则会与基础部件保持同步。