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

  1. Move the IsUndoEnabled assignment outside the BeginChange/EndChange block.
  2. Defer the assignment until after EndChange completes (e.g. Dispatcher.BeginInvoke or a flag checked after EndChange).
  3. 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

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


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)