Recursos personalizados do SDK

Os recursos no SDK do Open XML estão disponíveis a partir da v2.14.0 que permitem que o comportamento e o estado sejam contidos no documento ou parte e personalizados sem reimplementar o pacote ou parte que o contém. Isso é acessado por meio da Features propriedade em pacotes, partes e elementos.

Esta é uma implementação do padrão de estratégia que facilita a substituição do comportamento em tempo real. Ele é modelado após os recursos de solicitação no ASP.NET Core.

Herança de recursos

Pacotes, peças e elementos têm sua própria coleção de recursos. No entanto, eles também herdarão a parte e o pacote contendo, se estiverem disponíveis.

Para destacar isso, veja o caso de teste abaixo:

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
{
}

Observação

A coleção de recursos em elementos é somente leitura. Isso ocorre devido a problemas de memória se ele for gravado. Se isso for necessário, entre em https://github.com/dotnet/open-xml-sdk contato para nos informar seu cenário.

Visualizando recursos registrados

As implementações nativas do IFeatureCollection fornecem uma exibição de depuração útil para que você possa ver quais recursos estão disponíveis e quais são suas propriedades/campos:

Recursos Depurar Exibir

Recursos disponíveis

Os recursos atualmente disponíveis são descritos abaixo e em que escopo eles estão disponíveis:

IDisposableFeature

Esse recurso permite registrar ações que precisam ser executadas quando um pacote ou uma peça é destruída ou descartada:

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 */);

Pacotes e partes terão suas próprias implementações desse recurso. Os elementos recuperarão o elemento para a parte que o contém, se disponível.

IPackageEventsFeature

Esse recurso permite receber notificações de eventos quando um pacote é alterado:

OpenXmlPackage package = GetSomePackage();
package.TryAddPackageEventsFeature();

var feature = package.Features.GetRequired<IPackageEventsFeature>();

Observação

Pode haver ocasiões em que o pacote é alterado, mas um evento não é disparado. Nem todas as áreas foram identificadas onde faria sentido levantar um evento. Registre um problema se você encontrar um.

IPartEventsFeature

Esse recurso permite receber notificações de eventos de quando um evento está sendo criado. Este é um recurso adicionado à peça ou ao pacote:

OpenXmlPart part = GetSomePackage();
package.AddPartEventsFeature();

var feature = part.Features.GetRequired<IPartEventsFeature>();

Em geral, suponha que possa haver uma implementação singleton para os eventos e verifique se a parte é a parte correta.

Observação

Pode haver ocasiões em que a peça é alterada, mas um evento não é disparado. Nem todas as áreas foram identificadas onde faria sentido levantar um evento. Registre um problema se você encontrar um.

IPartRootEventsFeature

Esse recurso permite obter notificações de eventos de quando uma raiz de peça está sendo modificada/carregada/criada/etc. Este é um recurso que é adicionado ao recurso de nível de peça:

OpenXmlPart part = GetSomePart();
part.AddPartRootEventsFeature();

var feature = part.Features.GetRequired<IPartRootEventsFeature>();

Em geral, suponha que possa haver uma implementação singleton para os eventos e verifique se a parte é a parte correta.

Observação

Pode haver momentos em que a raiz da parte é alterada, mas um evento não é acionado. Nem todas as áreas foram identificadas onde faria sentido levantar um evento. Registre um problema se você encontrar um.

IRandomNumberGeneratorFeature

Esse recurso permite que um serviço compartilhado gere números aleatórios e preencha uma matriz.

IParagraphIdGeneratorFeature

Esse recurso permite o preenchimento e o acompanhamento de elementos que contêm IDs de parágrafo. Por padrão, isso garantirá a exclusividade de valores e garantirá que os valores existentes sejam válidos de acordo com as restrições do padrão. Para usar esse recurso:

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

Esse recurso também pode ser usado para garantir a exclusividade entre vários documentos com uma pequena alteração:

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);