dotnet/wpf · error · InvalidOperationException

SR.TextContainerChangingReentrancyInvalid

Error message

SR.TextContainerChangingReentrancyInvalid

What it means

TextBlock.GetPositionFromPoint throws InvalidOperationException while a content change is in progress on the text container. Reentrancy during a TextContainer change (e.g. inside a TextChanged handler) would corrupt layout state, so the API refuses the call until the change completes.

Solutions

  1. Defer the call: Dispatcher.BeginInvoke(DispatcherPriority.Input, () => textBlock.GetPositionFromPoint(...)).
  2. Perform hit-testing outside change events, e.g. on mouse events instead of TextChanged.
  3. Check TextBlock content-change state before calling if you control the change scope.

Example fix

// before
void OnTextChanged(object s, TextChangedEventArgs e) =>
    var p = textBlock.GetPositionFromPoint(mousePoint, false);
// after
void OnTextChanged(object s, TextChangedEventArgs e) =>
    Dispatcher.BeginInvoke(DispatcherPriority.Input,
        new Action(() => textBlock.GetPositionFromPoint(mousePoint, false)));
Defensive patterns

Strategy: try-catch

Try / catch

try { var p = textBlock.GetPositionFromPoint(point, snapToText); }
catch (InvalidOperationException) { Dispatcher.BeginInvoke(() => textBlock.GetPositionFromPoint(point, snapToText)); }

Prevention

When it happens

Trigger: Calling GetPositionFromPoint from within a TextChanged/TextChanged-like event raised during an ongoing text container change; hit-testing during TextContainer.BeginChange/EndChange window.

Common situations: Custom caret/hover logic wired to TextChanged; automation hit-testing triggered synchronously by content edits; layout events re-entering the TextBlock mid-change.

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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/TextBlock.cs:389

        /// The closest TextPointer to the supplied Point, or null if
        /// snapToText is false and the supplied Point is not contained
        /// within any character bounding box.
        /// </returns>
        /// <exception cref="System.InvalidOperationException">
        /// Throws InvalidOperationException if layout is dirty.
        /// </exception>
        /// <remarks>
        /// The TextPointer returned always has its IsFrozen property set true
        /// and LogicalDirection property set towards a character hit by the point,
        /// or closest to this point.
        /// </remarks>
        public TextPointer GetPositionFromPoint(Point point, bool snapToText)
        {
            TextPointer position;

            if(CheckFlags(Flags.ContentChangeInProgress))
            {
                throw new InvalidOperationException(SR.TextContainerChangingReentrancyInvalid);
            }

            EnsureComplexContent();

            // Validate layout information on TextView.
            if (((ITextView)_complexContent.TextView).Validate(point))
            {
                position = (TextPointer)_complexContent.TextView.GetTextPositionFromPoint(point, snapToText);
            }
            else
            {
                position = snapToText ? new TextPointer((TextPointer)_complexContent.TextContainer.Start) : null;
            }

            // BUG: We must freeze a pointer before returning.

            return position;
        }

View on GitHub (pinned to 81131a70a4)