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
- Defer the call: Dispatcher.BeginInvoke(DispatcherPriority.Input, () => textBlock.GetPositionFromPoint(...)).
- Perform hit-testing outside change events, e.g. on mouse events instead of TextChanged.
- 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
- Never hit-test inside TextChanged handlers
- Defer with Dispatcher.BeginInvoke during edits
- Prefer mouse/pointer events for point queries
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
- SR.Automation_RecursivePublicCall
- SR.CannotModifyVisualChildrenDuringTreeWalk
- SR.DrawingGroup_AlreadyOpen
- SR.IllegalTreeChangeDetected
- SR.TextFormatterReentranceProhibited
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)