dotnet/wpf · error · ArgumentException

SR.MoreThanOneAttachedAnnotation

Error message

SR.MoreThanOneAttachedAnnotation

What it means

MarkedHighlightComponent.AddAttachedAnnotation throws ArgumentException(SR.MoreThanOneAttachedAnnotation) if the component already holds an attached annotation. Unlike HighlightComponent, a MarkedHighlightComponent (the visual markers for a highlight) represents exactly one attached annotation, so a second Add is a programming error.

Solutions

  1. Call RemoveAttachedAnnotation before adding a new annotation to the same component instance.
  2. Create a new MarkedHighlightComponent per attached annotation (this is what AnnotationService normally does).
  3. Check a public/internal IsAttached flag (or try to read the current annotation) before adding.

Example fix

// before
markedHighlight.AddAttachedAnnotation(newAttached);
// after
if (markedHighlight.AttachedAnnotation != null)
    markedHighlight.RemoveAttachedAnnotation(markedHighlight.AttachedAnnotation);
markedHighlight.AddAttachedAnnotation(newAttached);
Defensive patterns

Strategy: validation

Validate before calling

if (markedHighlight.AttachedAnnotation != null) markedHighlight.RemoveAttachedAnnotation(markedHighlight.AttachedAnnotation);

Type guard

static bool CanAcceptAnnotation(MarkedHighlightComponent c) => c.AttachedAnnotation == null;

Try / catch

try { component.AddAttachedAnnotation(a); } catch (ArgumentException) { component.RemoveAttachedAnnotation(component.AttachedAnnotation); component.AddAttachedAnnotation(a); }

Prevention

When it happens

Trigger: Calling AddAttachedAnnotation twice on the same MarkedHighlightComponent instance without an intervening RemoveAttachedAnnotation; the AnnotationService routing two anchors to the same component.

Common situations: Duplicated anchors resolved by a custom LocatorPart to the same component; re-enabling a service without disabling first; loading overlapping annotations that resolve to one marker component.

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/c05e1720cbd05ad6. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Component/MarkedHighlightComponent.cs:203

            //after the content reflow
            if (_attachedAnnotation == null)
                throw new InvalidOperationException(SR.InvalidAttachedAnnotation);

            HighlightAnchor.GetDesiredTransform(transform);

            return transform;
        }

        /// <summary>
        /// Add an attached annotation to the component. The attached anchor will be used to add
        /// a highlight to the appropriate TextContainer
        /// </summary>
        /// <param name="attachedAnnotation">The attached annotation to be added to the component</param>
        public void AddAttachedAnnotation(IAttachedAnnotation attachedAnnotation)
        {
            if (_attachedAnnotation != null)
            {
                throw new ArgumentException(SR.MoreThanOneAttachedAnnotation);
            }

            //fire trace event
            EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordAnnotation, EventTrace.Event.AddAttachedMHBegin);

            //save the attached annotation
            _attachedAnnotation = attachedAnnotation;

            //create anchor markers
            if ((attachedAnnotation.AttachmentLevel & AttachmentLevel.StartPortion) != 0)
                _leftMarker = CreateMarker(GetMarkerGeometry());
            if ((attachedAnnotation.AttachmentLevel & AttachmentLevel.EndPortion) != 0)
                _rightMarker = CreateMarker(GetMarkerGeometry());

            //create highlight, markers and register for TextSelection.Changed and other events
            RegisterAnchor();

            //fire trace event

View on GitHub (pinned to 81131a70a4)