{"record":{"id":"21492b4507967384","repo":"dotnet/wpf","slug":"sr-arrangereentrancyinvalid","errorCode":null,"errorMessage":"SR.ArrangeReentrancyInvalid","messagePattern":"SR\\.ArrangeReentrancyInvalid","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/TextBlock.cs","lineNumber":3564,"sourceCode":"        // ------------------------------------------------------------------\n        private bool CheckFlags(Flags flags)\n        {\n            return ((_flags & flags) == flags);\n        }\n\n        // ------------------------------------------------------------------\n        // Ensures none of our public (or textview) methods can be called during measure/arrange/content change.\n        // ------------------------------------------------------------------\n        private void VerifyReentrancy()\n        {\n            if(CheckFlags(Flags.MeasureInProgress))\n            {\n                throw new InvalidOperationException(SR.MeasureReentrancyInvalid);\n            }\n\n            if(CheckFlags(Flags.ArrangeInProgress))\n            {\n                throw new InvalidOperationException(SR.ArrangeReentrancyInvalid);\n            }\n\n            if(CheckFlags(Flags.ContentChangeInProgress))\n            {\n                throw new InvalidOperationException(SR.TextContainerChangingReentrancyInvalid);\n            }\n        }\n\n        /// <summary>\n        /// Returns index of the line that starts at the given dcp. Returns -1 if\n        /// no line or the line metrics collection starts at the given dcp\n        /// </summary>\n        /// <param name=\"dcpLine\">\n        /// Start dcp of required line\n        /// </param>\n        private int GetLineIndexFromDcp(int dcpLine)\n        {\n            Invariant.Assert(dcpLine >= 0);","sourceCodeStart":3546,"sourceCodeEnd":3582,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/TextBlock.cs#L3546-L3582","documentation":"TextBlock throws this InvalidOperationException when a public or text-view method is re-entered while the Arrange (layout) pass is in progress. Arrangement positions the measured lines; reentrant calls could observe or mutate half-arranged state, so VerifyReentrancy() rejects them.","triggerScenarios":"Calling public TextBlock members (text mutation via Text/Inlines, TextRange operations, textview queries like GetLineText) from ArrangeOverride, from a Arrange-time callback, or from code triggered synchronously during the arrange pass (e.g. SizeChanged/Render handlers that feed back into the TextBlock).","commonSituations":"SizeChanged or LayoutUpdated handlers that change Text or Inlines, causing another layout; custom panels arranging a TextBlock and also mutating its content; UIA clients resolving range/line APIs during arrange.","solutions":["Defer the offending call with Dispatcher.BeginInvoke(DispatcherPriority.Background) so it runs after arrange completes.","In SizeChanged/LayoutUpdated handlers, do not write Text/Inlines directly; guard with a re-entrancy flag of your own and schedule the update.","For derived controls, keep ArrangeOverride read-only on the TextBlock's content and perform mutations from user-input or data-change handlers instead.","If the query is from automation, return cached metrics and refresh on a later dispatcher priority rather than re-entering immediately."],"exampleFix":"// before: rewriting text on SizeChanged\nvoid OnTextBlockSizeChanged(object s, SizeChangedEventArgs e)\n{\n    textBlock.Text = TrimToFit(textBlock.Text); // throws ArrangeReentrancyInvalid during arrange\n}\n\n// after: defer until layout is idle\nvoid OnTextBlockSizeChanged(object s, SizeChangedEventArgs e)\n{\n    Dispatcher.BeginInvoke(DispatcherPriority.Background,\n        new Action(() => textBlock.Text = TrimToFit(textBlock.Text)));\n}","handlingStrategy":"try-catch","validationCode":"bool insideArrange = !textBlock.IsArrangeValid; // if false, an arrange pass is likely running\nif (insideArrange) Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(ApplyChange));","typeGuard":"static bool ArrangeSafe(TextBlock tb) => tb.IsArrangeValid;","tryCatchPattern":"try\n{\n    UpdateTextBlock();\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"arrange\"))\n{\n    Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(UpdateTextBlock));\n}","preventionTips":["Keep SizeChanged/LayoutUpdated handlers free of Text/Inline writes.","Use your own bool re-entrancy flag around text updates.","Apply content changes in response to user input or data events, not layout callbacks.","Defer with DispatcherPriority.Background to guarantee arrange has finished."],"tags":["wpf","layout","reentrancy","invalidoperation"],"backgroundTag":"invalid-state-transition","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-22T01:17:13.364Z"}