10

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

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

现在我明白为什么会出现这种情况(因为它是一个活动的可撤销事件),但是如果用户输入了无效字符,我可以通过什么事件对文本框执行验证并撤消更改?

4

3 回答 3

12

回答 simbay 的方法,我认为它被驳回了。

您不能在 TextChanged 中调用 Undo,因为 TextBox 仍在准备撤消操作。它似乎有时有效,有时无效,因此这表明在发出事件信号和完成撤消准备之间存在竞争条件。

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

仅当您想防止输入或粘贴无效字符时,“接受的答案”才很棒,但总的来说,我经常对 TextBox 输入进行更多涉及的验证并希望验证最终文本值。从预览事件中辨别最终文本并不容易,因为就控件而言,还没有发生任何事情。

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

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

我已经阅读了很多关于文本框验证的狂野冒险,这和我发现的一样简单。

于 2014-08-22T18:02:59.603 回答
8

您应该使用PreviewTextInputandDataObject.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();
            }
        }
    }
}
于 2012-06-20T10:03:18.317 回答
4

从来自 TextChanged 事件处理程序中异步调用撤消:

Dispatcher.BeginInvoke(new Action(() => tb.Undo())) 
于 2013-08-19T12:14:48.383 回答