Невозможно использовать отмену в TextChanged

при использовании textbox.Undo (); я получаю следующую ошибку:

Не удается отменить или повторить, пока undo unit открыт.

теперь я понимаю, почему это так (потому что это активное событие undoable), но через какое событие я могу выполнить проверку на текстовом поле и отменить изменение, если пользователь набрал недопустимый символ?

3 ответов


вместо использования отмены и TextChanged, вы должны использовать PreviewTextInput и DataObject.Pasting событий. В PreviewTextInput обработчик событий, set e.Handled значение true, если введенный текст является недопустимым символом. В Pasting обработчик события e.CancelCommand() если вставленный текст является недействительным.

вот пример для текстового поля, который принимает только цифры 0 и 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>

код:

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();
            }
        }
    }
}

ответить симбай подход, который я думаю, увольняют.

вы не можете вызвать отмену в TextChanged, потому что операция отмены все еще готовится текстовым полем. Кажется, что это работает иногда, а не в другое время, поэтому это предполагает, что существует условие гонки между сигналом о событии и завершением подготовки отмены.

однако вызов отмены, вызванный диспетчером, позволит текстовому полю завершить подготовку отмены. Вы можете проверьте результаты изменения текста, а затем решите, хотите ли вы сохранить или отменить изменение. Это может быть не лучший подход, но я попробовал его и взорвал кучу текстовых изменений и вставок в текстовое поле и не смог воспроизвести исключение.

"принятый ответ" Отлично подходит, только если вы хотите предотвратить ввод или вставку недопустимого символа, но в целом я часто делаю гораздо более сложную проверку ввода TextBox и хочу проверить окончательное текстовое значение. Свой нелегко различить окончательный текст из события предварительного просмотра, потому что для элемента управления ничего еще не произошло.

чтобы ответить на вопрос Terribad, в ответ симбай лучше и более емко в нескольких ситуациях.

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

Я прочитал много диких приключений в проверке текстового поля, и это примерно так же просто, как я нашел.


вызовите отмену асинхронно из обработчика событий From the TextChanged:

Dispatcher.BeginInvoke(new Action(() => tb.Undo()))