无法在TextChanged中使用撤消

Ant*_*ain 9 c# wpf undo

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

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

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

Chr*_*sCW 9

回答simbay的方法,我认为这是被解雇的.

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

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

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

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

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

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


小智 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>
Run Code Online (Sandbox Code Playgroud)

代码背后:

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();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)