dotnet/wpf · error · InvalidOperationException
SR.TextBoxBase_CantSetIsUndoEnabledInsideChangeBlock
Error message
SR.TextBoxBase_CantSetIsUndoEnabledInsideChangeBlock
What it means
Setting IsUndoEnabled on a TextBoxBase while a change block (BeginChange...EndChange) is open is rejected with an InvalidOperationException. Toggling the undo manager inside a change block would corrupt the undo stack, so WPF forbids it. The check runs in the IsUndoEnabled property-change callback.
Solutions
- Move the IsUndoEnabled assignment outside the BeginChange/EndChange block.
- Defer the assignment until after EndChange completes (e.g. Dispatcher.BeginInvoke or a flag checked after EndChange).
- If you must reconfigure undo, end the current change block first, then set the property, then begin a new block.
Example fix
// before textBox.BeginChange(); textBox.IsUndoEnabled = false; // throws inside change block textBox.EndChange(); // after textBox.BeginChange(); textBox.EndChange(); textBox.IsUndoEnabled = false;
Defensive patterns
Strategy: validation
Validate before calling
bool isInsideChangeBlock = textBox.IsSelectionActive && GetChangeBlockLevel(textBox) > 0; // helper using reflection over TextEditor.Selection.ChangeBlockLevel if (!isInsideChangeBlock) textBox.IsUndoEnabled = false;
Try / catch
try
{
textBox.IsUndoEnabled = false;
}
catch (InvalidOperationException)
{
Dispatcher.BeginInvoke(new Action(() => textBox.IsUndoEnabled = false), DispatcherPriority.Background);
} Prevention
- Configure IsUndoEnabled only at control initialization
- Never mutate undo settings inside TextChanged or BeginChange blocks
- Defer property writes with Dispatcher when reacting to edit events
When it happens
Trigger: Assigning textBox.IsUndoEnabled = false (or true) inside a BeginChange()/EndChange() block, including from code invoked by a property-changed handler or TextChanged event raised during the block.
Common situations: Undo configuration code that reacts to TextChanged and tries to disable undo mid-edit; refactoring that moved a property setter inside an edit transaction.
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.TextBoxBase_UnmatchedEndChange
- SR.UndoNoOpenUnit
- SR.UndoServiceDisabled
- SR.UndoUnitAlreadyOpen
- SR.UndoUnitCantBeOpenedTwice
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/cd8271d755f8a80f.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/Primitives/TextBoxBase.cs:1627
}
}
/// <summary>
/// Helper method to update the IsUndoEnabled flag within UndoManager
/// attached to the TextBox.
/// </summary>
/// <param name="value">
/// New Value of IsUndoEnabled flag.
/// </param>
internal void ChangeUndoEnabled(bool value)
{
// REVIEW:benwest:9/1/2005: does throwing exceptions here really work?
// Isn't the property value already changed? We don't want the property value
// to change....
if (this.TextSelectionInternal.ChangeBlockLevel > 0)
{
throw new InvalidOperationException(SR.TextBoxBase_CantSetIsUndoEnabledInsideChangeBlock);
}
UndoManager undoManager = UndoManager.GetUndoManager(this);
if (undoManager != null)
{
if (!value && undoManager.IsEnabled)
{
undoManager.Clear();
}
undoManager.IsEnabled = value;
}
}
/// <summary>
/// Helper method to update the UndoLimit in UndoManager
/// attached to the TextBox.
/// </summary>
/// <param name="value">View on GitHub (pinned to 81131a70a4)