dotnet/wpf · error · InvalidOperationException

SR.AnnotationServiceNotEnabled

Error message

SR.AnnotationServiceNotEnabled

What it means

AnnotationService.Disable throws this InvalidOperationException when the service has not been enabled (the internal _isEnabled flag is false). Disable is only valid after a successful Enable call on the same service instance.

Solutions

  1. Guard the Disable call with AnnotationService.GetService(viewer) != null or a tracked bool before calling it.
  2. Structure teardown so Disable is called exactly once per Enable (e.g. set the service field to null after disabling).

Example fix

// before
service.Disable();
// after
if (AnnotationService.GetService(myViewer) is AnnotationService service)
    service.Disable();
Defensive patterns

Strategy: type-guard

Validate before calling

bool isEnabled = AnnotationService.GetService(myViewer) != null;

Type guard

bool CanDisable(AnnotationService s) => AnnotationService.GetService(s != null ? GetViewer(s) : null) != null;

Try / catch

try { service.Disable(); } catch (InvalidOperationException) { /* never enabled; ignore */ }

Prevention

When it happens

Trigger: Calling Disable() on a service that was never enabled, or calling Disable() twice (double-teardown, e.g. in both a page unload handler and a Dispose method).

Common situations: See trigger scenarios.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/29b08debf02579a1. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Annotations/AnnotationService.cs:225

            // Don't register on the store until the service is ready to accept events.
            // Register for content change and anchor change events - we'll need to attach/detach
            // annotations as they are added/removed from the store or their anchors change
            annotationStore.StoreContentChanged += new StoreContentChangedEventHandler(OnStoreContentChanged);
            annotationStore.AnchorChanged += new AnnotationResourceChangedEventHandler(OnAnchorChanged);
        }

        /// <summary>
        ///     Disables annotations on the DocumentViewerBase.  Any visible annotations will
        ///     disappear.  Service can be enabled again by calling Enable.
        /// </summary>
        /// <exception cref="InvalidOperationException">service isn't enabled</exception>
        public void Disable()
        {
            VerifyAccess();

            if (!_isEnabled)
                throw new InvalidOperationException(SR.AnnotationServiceNotEnabled);

            // If it hasn't been run yet, abort the pending operation.  Still need to
            // unregister and unload annotations.  They may have been loaded due to a
            // store event.
            _asyncLoadOperation?.Abort();
            _asyncLoadOperation = null;

            // Unregister for changes to the store - add/deletes/anchor changes - before
            // unloading annotations.  We don't want any events between unloading and unregistering.
            try
            {
                _store.StoreContentChanged -= new StoreContentChangedEventHandler(OnStoreContentChanged);
                _store.AnchorChanged -= new AnnotationResourceChangedEventHandler(OnAnchorChanged);
            }
            finally
            {
                IDocumentPaginatorSource document;
                DocumentViewerBase viewer;

View on GitHub (pinned to 81131a70a4)