Starting with GroupDocs.Conversion for .NET v26.6, conversion event handlers are aggregated into a single typed object — ConversionEvents. This replaces three previously separate registration paths:
Per-result handler properties on ConverterSettings (OnConversionFailed, OnConversionByPageFailed, OnCompressionCompleted).
The fluent chain methods placed after WithOptions(...) or Compress(...) (.OnConversionCompleted(...), .OnConversionFailed(...), .OnCompressionCompleted(...)).
The aggregator is registered with the Converter constructor via a new events: factory parameter, or with the fluent API via the entry-stage FluentConverter.WithEvents(...) method.
Event groups
ConversionEvents exposes two distinct groups of handlers.
Pipeline lifecycle
Fire once per conversion run, regardless of how many documents or pages the run produces. These replace the Started / Progress / Completed callbacks of IConverterListener.
Handler
Signature
When it fires
OnConversionStarted
Action
Once, when the conversion pipeline starts
OnConversionProgress
Action<byte>
While the pipeline is running, with the current progress percentage (0–100)
OnConversionCompleted
Action
Once at the end of the pipeline, regardless of success or failure
Name reuse — read before upgrading
The OnConversionCompleted name is reused with new semantics in v26.6. The pre-v26.6 fluent chain method .OnConversionCompleted(Action<ConvertedContext>) (per-document) is now OnDocumentConverted on the aggregator. The new ConversionEvents.OnConversionCompleted is a lifecycle handler — its signature is Action (no parameters) and it fires once at pipeline end. If you copy a v26.5-and-earlier example expecting per-document context, switch to OnDocumentConverted.
Per-result
Fire once per produced item — each converted document, each converted page, each compressed archive — including failures.
Handler
Signature
When it fires
OnDocumentConverted
Action<ConvertedContext>
After each document conversion completes successfully
OnDocumentFailed
Action<ConvertContext, Exception>
When a document conversion throws
OnPageConverted
Action<ConvertedPageContext>
After each page is converted in page-by-page conversions
OnPageFailed
Action<ConvertContext, Exception>
When a single page fails during page-by-page conversion
The fluent API exposes a single entry-stage method — WithEvents — that accepts a builder action and replaces the per-method chain previously placed after ConvertTo(...).WithOptions(...):
WithEvents is an early-stage call — it must appear before Load(...). It can be combined with WithSettings(...) in either order.
Global vs per-call handlers
Handlers registered on ConversionEvents are global — they live for the lifetime of the Converter instance and fire on every Convert(...) call:
using(varconverter=newConverter("source.docx",()=>newConverterSettings(),()=>events)){converter.Convert("page1.pdf",newPdfConvertOptions());// events.OnDocumentConverted firesconverter.Convert("page2.tiff",newTiffConvertOptions());// same global handler fires again}
Convert(...) overloads that accept an Action<ConvertedContext> register a per-call result handler that wins over the global OnDocumentConverted for that single call:
using(varconverter=newConverter("source.docx",()=>newConverterSettings(),()=>events)){// Per-call handler — overrides events.OnDocumentConverted for THIS call onlyconverter.Convert(newPdfConvertOptions(),(ConvertedContextctx)=>{using(varfileStream=File.Create("custom.pdf")){ctx.ConvertedStream.CopyTo(fileStream);}});// No per-call handler — events.OnDocumentConverted firesconverter.Convert("page2.pdf",newPdfConvertOptions());}
The precedence rule is (perCall ?? global)?.Invoke(...): if a per-call handler is supplied, the global OnDocumentConverted does not fire for that call. The other per-result handlers (OnDocumentFailed, OnPageConverted, OnPageFailed, OnCompressionCompleted) and all lifecycle handlers are always global — there is no per-call override.
Between consecutive Convert(...) calls on the same Converter, only the per-call slot is reset. The global ConversionEvents bag is preserved across runs.
Handling compressed archive output
When converting and re-compressing archive contents (see Extract and Convert Archive Contents), OnCompressionCompleted is invoked once the new archive stream is ready:
The previous late-stage .OnCompressionCompleted(stream => ...) placed after .Compress(...) continues to work but is obsolete — the IConversionCompressResultCompleted interface that declares it is planned for removal in v26.9.
Compatibility with the previous API
The previous registration mechanisms continue to work, but are obsolete and planned for removal in v26.9:
When values are set on both the obsolete locations and on ConversionEvents, the aggregator wins. Handlers set on ConverterSettings (including a Listener instance) are forwarded into the internal events bag at converter construction.