Unable to use Undo in TextChanged

c#, undo, wpf

Solution

Instead of using Undo and TextChanged, you should use the `PreviewTextInput` and `DataObject.Pasting` events. In the `PreviewTextInput` event handler, set `e.Handled` to true if the typed text is an invalid character. In the `Pasting` event handler, call `e.CancelCommand()` if the pasted text is invalid.

Here is an example for a text box that accepts only the digits 0 and 1:

XAML:

<Window x:Class="BinaryTextBox.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="133" Width="329">
    <StackPanel>
        <TextBox x:Name="txtBinary" Width="100" Height="24"
                 PreviewTextInput="txtBinary_PreviewTextInput"
                 DataObject.Pasting="txtBinary_Pasting"/>
    </StackPanel>
</Window>

Code behind:

using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Input;

namespace BinaryTextBox
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void txtBinary_PreviewTextInput(object sender,
                 TextCompositionEventArgs e)
        {
            e.Handled = e.Text != "0" && e.Text != "1";
        }

        private void txtBinary_Pasting(object sender, DataObjectPastingEventArgs e)
        {
            if (!Regex.IsMatch(e.DataObject.GetData(typeof(string)).ToString(), "^[01]+$"))
            {
                e.CancelCommand();
            }
        }
    }
}

Problem

When using textbox.Undo(); I get the following error: Cannot Undo or Redo while undo unit is open. Now I understand why this is the case (because it is an active undoable event) but through what event can I perform validation on a text box and undo the change if the user has typed an invalid character?

Original source