WPF - MVVM Textbox restrict to specific characters

后端 未结 4 952
有刺的猬
有刺的猬 2021-01-14 01:42

I am trying to make text box accept only specific characters.

My TextBox is bound to the following:

    private string _CompanyID;
    public string          


        
相关标签:
4条回答
  • 2021-01-14 02:00

    You should use a custom UI element there that restricts the input on the view-side using “classic” solutions like change listeners.

    For example, you can just create a simple subtype of TextBox that overrides the OnPreviewTextInput method. There, you can decide when some input should go through, or when you want to prevent it.

    For example, this is a custom TextBox that takes only characters from the ASCII alphabet:

    public class AlphabetTextBox : TextBox
    {
        private static readonly Regex regex = new Regex("^[a-zA-Z]+$");
    
        protected override void OnPreviewTextInput(TextCompositionEventArgs e)
        {
            if (!regex.IsMatch(e.Text))
                e.Handled = true;
            base.OnPreviewTextInput(e);
        }
    }
    

    Of course, you could also make the regular expression a property of the text box and allow people to set it from XAML. That way, you would get a very reusable component which you can use for various applications.

    0 讨论(0)
  • 2021-01-14 02:04

    Public Shared Function GetWordCount(str As String) As Integer Dim collection As MatchCollection = Regex.Matches(str, "\S+") Return collection.Count End Function

    Public Shared Function GetInWordLimit(str As String, max_words As Integer) As String

        Dim final As String = ""
        Dim count As Integer = Core.StringOperations.GetWordCount(str)
        Dim avg_max_length As Integer = max_words * 7
    
        Dim words = str.Split(" ")
        If (words.Length > max_words - 1 And count > max_words - 1) Then
            Dim index As Integer = 0
            For Each word In words
                If index >= max_words Then Exit For
    
                final &= word & " "
                If Not (Char.IsSeparator(word) Or Char.IsWhiteSpace(word) Or word = "") Then
                    index += 1
                End If
    
            Next
            final = final.TrimEnd
        Else
            final = str
        End If
    
            If final.Length > avg_max_length - 1 Then final = final.Substring(0, avg_max_length)
    
        Return final
    End Function
    
    0 讨论(0)
  • 2021-01-14 02:07

    I do this with the PreviewtextInput event. I have a generic event used for multiple TextBoxes which takes the regex from a configuration table, but I have hard-coded the regex in this example.

    private void GenericTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
    {
       e.Handled = !IsTextAllowed(e.Text, @"[^a-zA-Z]");
    }
    
    private static bool IsTextAllowed(string Text, string AllowedRegex)
    {
        try
        {
            var regex = new Regex(AllowedRegex);
            return !regex.IsMatch(Text);
        }
        catch
        {
            return true;
        }
    }
    
    0 讨论(0)
  • 2021-01-14 02:23

    The problem is, humans type in numbers sequentially, the fools.
    To type in "0.1", a legitimate string, you have to type in "0.", which fails. Also, re the accepted answer from @poke (which is great), the e.Text value is the change to the textbox (keystroke).
    You must add this change to the current textbox string, and then validate the concatenated candidate string, and see if that is valid. Humans are also wiley, so they will paste from the clipboard to get around the restriction.
    With a textbox, you will never be able to block all garbage in, because at some point the user will have to go through garbage, to get to a valid string.
    So you can block illegal character entry using e.Text, or allow sequential step failure. But you will still have to check the final string for validity too.
    Below is an example of a textbox that allows users to type in a decimal value with a max of 8 dec places in, but they could still cheat this by pasting from the clipboard.

    ////////////////////////
    // REGEXTEXTBOX CLASS //
    ////////////////////////
    
    
    using System.Windows.Controls; // Textbox
    using System.Windows.Input;
    using System.Text.RegularExpressions; // Regex
    
    namespace MyNamespace
    {
        public class RegexTextBox : TextBox
        {
            private Regex _regex = null;
    
            public Regex Regex
            {
                get { return _regex; }
                set { _regex = value; }
            }
    
    
            ///////////////////////////////////////////////////////////////////////
            // MEMBERS
    
            protected override void OnPreviewTextInput(TextCompositionEventArgs e)
            {
                var prefix = "OnPreviewTextInput() - ";
                logger.Debug(prefix + "Entering");
    
                string currentText = this.Text;
                string candidateText = currentText + e.Text;
    
                // If we have a set regex, and the current text fails,
                // mark as handled so the text is not processed.
                if (_regex != null && !_regex.IsMatch(candidateText))
                {
                    e.Handled = true;
                }           
    
                base.OnPreviewTextInput(e);
            }
    
        } // end of class RegexTextbox
    
    } // end of MyNamespace
    
    
    /////////////////////
    // MAINWINDOW.XAML //
    /////////////////////
    
    //(Window class needs to know your namespace so it needs xmlns:myNamespace="clr-namespace:MyNamespace")
    
    <myNamespace:RegexTextBox 
     x:Name="textboxPayToAmount" 
     Text="{Binding PayToAmount}">
    </myNamespace:RegexTextBox> 
    
    
    ////////////////////////
    // MAINWINDOW.XAML.CS //
    ////////////////////////
    
    namespace MyNamespace
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
                textboxPayToAmount.Regex = 
                    new System.Text.RegularExpressions.Regex(@"^\d*(\.\d{0,8})?$");
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题