Unable to use Undo in TextChanged

When using textbox.Undo (); I get the following error:

Cannot undo or redo until undo block is open.

Now I understand why this is so (because it is an active canceled event), but through which event can I check in the text field and cancel the change if the user types an invalid character?

+7
source share
3 answers

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

Here is an example of a text field that accepts only the numbers 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(); } } } } 
+6
source

To answer the simbay approach, which I think is fired.

You cannot invoke Undo in TextChanged because the undo operation is still being prepared by the TextBox. It seems that this works sometimes, and not at another time, so this suggests that there is a race condition between when the event is signaled and the cancellation is completed.

However, a Undo call called in Dispatcher will allow the text field to complete its undo preparation. You can check the results of the text change, and then decide whether you want to save or cancel the change. This may not be the best approach, but I tried it and blew up a bunch of text changes and inserts into the text box and couldn't throw an exception.

The โ€œaccepted answerโ€ is great ONLY if you want to prevent the input or insertion of an invalid character, but overall I often do a much more active confirmation of the TextBox input and want to check the final value of the text. It is not easy to see the final text from the preview, because, as far as management is concerned, nothing has happened.

To answer the question of Terribad, the simbay answer is better and more concise in more situations.

 tb.TextChanged =+ (sender, args ) => { if(! MeetsMyExpectations(tb.Text) ) Dispatcher.BeginInvoke(new Action(() => tb.Undo())); } 

I read a lot of wild adventures in checking a text box, and it's about as simple as I found.

+7
source

Call cancellation asynchronously from the From TextChanged event handler:

 Dispatcher.BeginInvoke(new Action(() => tb.Undo())) 
+3
source

All Articles