当使用 textbox.Undo(); 我收到以下错误:
撤消单元打开时无法撤消或重做。
现在我明白为什么会出现这种情况(因为它是一个活动的可撤销事件),但是如果用户输入了无效字符,我可以通过什么事件对文本框执行验证并撤消更改?
回答 simbay 的方法,我认为它被驳回了。
您不能在 TextChanged 中调用 Undo,因为 TextBox 仍在准备撤消操作。它似乎有时有效,有时无效,因此这表明在发出事件信号和完成撤消准备之间存在竞争条件。
然而,在 Dispatcher 上调用 Undo 将允许文本框完成其撤消准备。您可以验证文本更改的结果,然后决定是否要保留或撤消更改。这可能不是最好的方法,但我尝试了它并将一堆文本更改和粘贴到文本框中,并且无法重现异常。
仅当您想防止输入或粘贴无效字符时,“接受的答案”才很棒,但总的来说,我经常对 TextBox 输入进行更多涉及的验证并希望验证最终文本值。从预览事件中辨别最终文本并不容易,因为就控件而言,还没有发生任何事情。
要回答 Terribad 的问题,simbay 的回答在更多情况下更好更简洁。
tb.TextChanged += ( sender, args ) =>
{
if(! MeetsMyExpectations( tb.Text ) )
Dispatcher.BeginInvoke(new Action(() => tb.Undo()));
};
我已经阅读了很多关于文本框验证的狂野冒险,这和我发现的一样简单。
您应该使用PreviewTextInput
andDataObject.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();
}
}
}
}
从来自 TextChanged 事件处理程序中异步调用撤消:
Dispatcher.BeginInvoke(new Action(() => tb.Undo()))