【问题标题】:Canceling TextBox input on validation error in WPF在 WPF 中取消验证错误时的 TextBox 输入
【发布时间】:2010-02-02 22:18:45
【问题描述】:

我试图弄清楚当发生验证错误时如何取消TextBox 中的用户输入。如果用户尝试输入无效字符,我想阻止它被添加到TextBox

如何添加或修改以下代码以防止TextBox 接受无效字符?不听TextBox.TextChanged事件有可能吗?

我的TextBox 看起来像:

<TextBox Validation.Error="OnSomeTextBoxValidationError">
    <TextBox.Text>
        <Binding Path="Value" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                 <local:SomeValidationRule />
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

我的自定义验证规则如下所示:

public class SomeValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        string hex_string = value as string;
        Match invalid_chars = Regex.Match(hex_string, "[^0-9a-fA-F]");
        bool is_valid = (invalid_chars.Success == false);
        string error_context = null;

        if (is_valid == false)
        {
            error_context = "Invalid characters";
        }

        return new ValidationResult(is_valid, error_context);
    }
}

我有一个错误处理程序...我可以用它做些什么吗?

private void OnSomeTextBoxValidationError(object sender, ValidationErrorEventArgs e)
{
    // Can I do anything here?
}

如果可能,请提供原始答案,而不是引用 URL。我已经阅读了很多涉及事件处理程序的可能解决方案,但我没有遇到任何人讨论在 ValidationRule 中进行所有验证的可能性。

【问题讨论】:

    标签: wpf validation textbox


    【解决方案1】:

    经过大量研究,似乎完全控制TextBox 的输入的唯一方法是直接处理多个事件。根据 C# 2008 中的 WPF 食谱(第 1 版,第 169 页):

    不幸的是,(目前)没有简单的方法将有用的高级数据绑定功能与防止用户完全输入无效字符所必需的低级键盘处理相结合。

    这是我想出的创建十六进制数字TextBox 的方法,它只接受字符 a-f、A-F 和 0-9。

    SomeClass.xaml

    <TextBox
        x:Name="SomeTextBox"
        LostFocus="TextBoxLostFocus"
        PreviewKeyDown="TextBoxPreviewKeyDown"
        PreviewTextInput="TextBoxPreviewTextInput" />
    

    SomeClass.xaml.cs

    private string mInvalidCharPattern = "[^0-9a-fA-F]";
    
    // In my case SomeClass derives from UserControl
    public SomeClass()
    {
        DataObject.AddPastingHandler(
            this.SomeTextBox,
            new DataObjectPastingEventHandler(TextBoxPasting));
    }
    
    private void TextBoxLostFocus(object sender, RoutedEventArgs e)
    {
        // You may want to refresh the TextBox's Text here. If the user deletes
        // the contents of the TextBox and clicks off of it, then you can restore
        // the original value.
    }
    
    // Catch the space character, since it doesn't trigger PreviewTextInput
    private void TextBoxPreviewKeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Space) { e.Handled = true; }
    }
    
    // Do most validation here
    private void TextBoxPreviewTextInput(object sender, TextCompositionEventArgs e)
    {
        if (ValidateTextInput(e.Text) == false) { e.Handled = true; }
    }
    
    // Prevent pasting invalid characters
    private void TextBoxPasting(object sender, DataObjectPastingEventArgs e)
    {
        string lPastingText = e.DataObject.GetData(DataFormats.Text) as string;
        if (ValidateTextInput(lPastingText) == false) { e.CancelCommand(); }
    }
    
    // Do the validation in a separate function which can be reused
    private bool ValidateTextInput(string aTextInput)
    {
        if (aTextInput == null) { return false; }
    
        Match lInvalidMatch = Regex.Match(aTextInput, this.mInvalidCharPattern);
        return (lInvalidMatch.Success == false);
    }
    

    【讨论】:

    【解决方案2】:

    您可能已经看过这个,但它是最简单的解决方案,并且一直对我有用。我捕捉到 PreviewKeyDown 事件和..

    <TextBox PreviewKeyDown="TextBox_PreviewKeyDown" Width="150" Height="30"></TextBox>
    
    private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        ... validation here, eg. to stop spacebar from being pressed, you'd use:
    
        if (e.Key == Key.Space) e.Handled = true;
    
    }
    

    【讨论】:

    • 我避免使用 PreviewKeyDown,因为我希望可以在 ValidationRule 中完成所有验证。这可能是我需要做的。在你的例子中提到空格键也很好。谢谢!
    • 没问题。我通常头脑简单,所以我的解决方案也很简单。 ;)
    • 不幸的是,KeyDown 只是将文本添加到 TextBox 的方法之一。其他的是粘贴或拖放。
    【解决方案3】:

    我将它用于 Windows Phone Runtime 8.1 应用程序以仅允许某些字符:

    <TextBox x:Name="TextBoxTitle" 
                     MaxLength="24" 
                     InputScope="AlphanumericHalfWidth" 
                     TextChanged="TextBoxTitle_TextChanged"                      
                     KeyUp="TextBoxTitle_KeyUp"
                     Paste="TextBoxTitle_Paste"/>
    
    using System.Text.RegularExpressions;
    
    bool textBoxTitle_TextPasted = false;
    private void TextBoxTitle_Paste(object sender, TextControlPasteEventArgs e)
    {
        textBoxTitle_TextPasted = true;
    }
    
    // only allow characters A-Z, a-z, numbers and spaces
    private void TextBoxTitle_TextChanged(object sender, TextChangedEventArgs e)
    {
        string fileNameCompatibleString = Regex.Replace(TextBoxTitle.Text, "[^a-zA-Z0-9\x20]", String.Empty);
        if (TextBoxTitle.Text != fileNameCompatibleString)
        {
            if (textBoxTitle_TextPasted)
            {
                TextBoxTitle.Text = fileNameCompatibleString;
                TextBoxTitle.SelectionStart = fileNameCompatibleString.Length;
            }
            else
            {
                int selectionStartSaved = TextBoxTitle.SelectionStart;
                TextBoxTitle.Text = fileNameCompatibleString;
                TextBoxTitle.SelectionStart = selectionStartSaved-1;
            }               
        }
        textBoxTitle_TextPasted = false;
    }
    
    // close SIP keyboard on enter key up
    private void TextBoxTitle_KeyUp(object sender, KeyRoutedEventArgs e)
    {
        if (e.Key == Windows.System.VirtualKey.Enter)
        {
            Windows.ApplicationModel.Core.CoreApplication.GetCurrentView().CoreWindow.IsInputEnabled = false;
            Windows.ApplicationModel.Core.CoreApplication.GetCurrentView().CoreWindow.IsInputEnabled = true;
            e.Handled = true;
        }       
    }

    【讨论】:

      【解决方案4】:

      在 TextBox PreviewKeyUp 事件之后运行良好。通过将发件人转换为 TextBox 来捕获文本框中的当前文本。然后使用正则表达式替换来替换无效字符。也可以在此处添加一些工具提示文本,但现在这会删除无效字符并将背景变为红色以便即时用户反馈。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-07-01
        • 1970-01-01
        • 2015-09-19
        • 1970-01-01
        • 1970-01-01
        • 2011-03-13
        • 1970-01-01
        相关资源
        最近更新 更多