无法在TextChanged中使用撤消

时间:2012-06-20 08:39:37

标签: c# wpf undo

使用textbox.Undo()时;我收到以下错误:

  

撤消单位打开时无法撤消或重做。

现在我理解为什么会出现这种情况(因为它是一个主动的可撤销事件)但是通过什么事件可以在文本框上执行验证并在用户输入无效字符时撤消更改?

3 个答案:

答案 0 :(得分:9)

回答simbay的方法,我认为这种做法正在被驳回。

您无法在TextChanged中调用撤消,因为TextBox仍在准备撤消操作。它似乎有时工作,而不是其他时间,所以这表明在事件发出信号和完成撤消准备之间存在竞争条件。

但是,在Dispatcher上调用Undo将允许文本框完成撤消准备。您可以验证文本更改的结果,然后确定是要保留还是撤消更改。这可能不是最好的方法,但我尝试了它并在文本框中抨击了一堆文本更改和粘贴,无法重现异常。

接受的答案"只有你想要防止输入或粘贴无效字符才是很好的,但一般来说我经常做更多涉及TextBox输入的验证并想要验证最终的文本值。从预览事件中识别最终文本并不容易,因为就控件而言,还没有发生任何事情。

回答Terribad的问题,simbay的答案在更多情况下更好,更简洁。

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

我已经在文本框验证中阅读了很多疯狂的冒险故事,这和我发现的一样简单。

答案 1 :(得分:8)

您应该使用PreviewTextInputDataObject.Pasting事件,而不是使用Undo和TextChanged。在PreviewTextInput事件处理程序中,如果键入的文本是无效字符,请将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();
            }
        }
    }
}

答案 2 :(得分:3)

从From TextChanged事件处理程序异步调用undo:

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