3

I have a textbox C# for IP addressing; validating IP address. However, I'm trying to limit to numbers and the amount of dots a user can enter in for the IP address. This way it limits errors.

Seems I'm able to enter one dot, I would like to increase that number to three. I can create a "Regex.IsMatch" and validate using "IPAddress", but I'm just trying to limit what the user can enter before pressing a button to proceed.

Is there a way to do this? Searching the Internet haven't found any way to do this.

    string pattern = @"\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b";
    bool CKDots = Regex.IsMatch(TracertIP, pattern);

    private void txtTracerouteIP_KeyPress(object sender, KeyPressEventArgs e)
    {
        // Enter only numbers.
        if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) && (e.KeyChar != '.'))
        {
            e.Handled = true;
        }
        // Only one dot, but I need three.
        //if ((e.KeyChar == '.') && ((sender as TextBox).Text.IndexOf('.') > -1))
        //{
        //    e.Handled = true;
        //}
    }
DemarcPoint
  • 183
  • 1
  • 9
  • Use [MaskedTextBox](https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.maskedtextbox?view=netframework-4.8). See [this](https://stackoverflow.com/a/18961474/10216583) for example. –  Mar 19 '20 at 22:39
  • 1
    I tried masking before but it requires three digits in each octet regardless. Most people are not accustomed to writing an IP address that way. For example 192.168.3.1 as opposed to 192.168.003.001. – DemarcPoint Mar 19 '20 at 23:30
  • Absolutely right. However validating that is easier with the MTB since you don't need to be worried about the dot part. Anyways Its just a suggestion. –  Mar 20 '20 at 10:27

2 Answers2

1

Since the MaskedTextBox is not an option and you prefer the TextBox, then maybe this would lead to something.

using System;
using System.Linq;
using System.Windows.Forms;
using System.ComponentModel;

namespace SomeNamespace
{
    [DesignerCategory("Code")]
    public class IPTextBox : TextBox
    {
        #region Constructors

        public IPTextBox() : base() { }

        #endregion

        #region Public Properties

        [Browsable(false)]
        public bool IsValidIP => IsValidInput(Text, true);

        #endregion

        #region Private Methods

        private bool IsValidInput() => IsValidInput(Text);

        private bool IsValidInput(string input, bool full = false)
        {
            var split = input.Split('.');
            var parts = split.Where(x => int.TryParse(x, out _));

            return !input.StartsWith(".")
                && !input.EndsWith("..")
                && !split.Any(x => x.Length > 1 && x.StartsWith("0"))
                && (full ? parts.Count() == 4 : split.Count() < 5)
                && parts.All(x => int.Parse(x) < 256);
        }

        #endregion

        #region Base

        protected override void OnTextChanged(EventArgs e)
        {
            if (Text.Trim().Length > 0 && !IsValidInput())
            {
                SendKeys.SendWait("{BS}");
                OnInvalidInput();
            }
            else
                base.OnTextChanged(e);
        }

        protected override void OnKeyPress(KeyPressEventArgs e)
        {           
            if (!char.IsControl(e.KeyChar)
                && !char.IsDigit(e.KeyChar)
                && e.KeyChar != '.')
            {
                e.Handled = true;
                OnInvalidInput();
            }
            else
                base.OnKeyPress(e);
        }

        private const int WM_PASTE = 0x0302;        

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_PASTE:
                    if (!IsValidInput(Clipboard.GetText()))
                        return;
                    break;
                default:
                    break;
            }
            base.WndProc(ref m);
        }

        #endregion

        #region Custom Events

        public event EventHandler InvalidInput;

        protected virtual void OnInvalidInput()
        {
            var h = InvalidInput;
            h?.Invoke(this, EventArgs.Empty);
        }

        #endregion
    }
}

Steps & Description


  • Derive a new class from TextBox control.

  • Override the OnKeyPress method to permit the control, digit, and . keys only.

  • Override the OnTextChanged method to validate the modified text thru the IsValidInput function and delete the last entered character if the function returns false.

  • The IsValidInput function checks whether the entered text can produce a valid IP address or a part of it.

  • The IsValidIP read-only property returns whether the text is a valid IP address. As you know, the IPAddress.TryParse(..) will also return true if you pass for example 1 or 192.168 because it parses them as 0.0.0.1 and 192.0.0.168 respectively. So it won't help here.

  • The custom event InvalidInput is raised whenever an invalid key is pressed and if the Text does not form a valid IP address or a part of it. So, the event can be handled in the implementation to alert the user if necessary.

That's it all.

IP Address TextBox

Related


How to TextBox inputs of custom format?

  • Greetings JQSOFT, I was testing your code, but got the errors: Syntax error and Invalid expression term 'int' – DemarcPoint Mar 23 '20 at 00:08
  • Thank you for responding. I'm not saying your code isn't working, just that programming is not my full-time job and I'm only doing it because I like it. However, with that in mind I sometimes miss little details. JQSOFT, when I create the class I get "Invalid expression term 'int'", so I added "private static int y;" and removed the (int) from int.TryParse(x, out y) and (int.TryParse(x, out y) &&). I suppose from this point I'm not really sure on how to use the class. Maybe that's where I'm getting confused. Could you elaborate? I do appreciate your help. :-) – DemarcPoint Mar 24 '20 at 16:13
  • @DemarcPoint What .NET Framework are you using? Check in the Project -> ProjectName.. Properties –  Mar 24 '20 at 16:33
  • @DemarcPoint Try the fix. And update that IDE for god sake :) –  Mar 24 '20 at 16:55
  • Okay, I had to also add "int y;" to "private bool IsValidInput". So now how do you use it? I'm not seeing "IsValidIP" show up anywhere in the list for IPTextBox. – DemarcPoint Mar 24 '20 at 17:23
  • @DemarcPoint Replace the two methods only, nothing else. –  Mar 24 '20 at 17:32
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/210248/discussion-between-demarcpoint-and-jqsoft). – DemarcPoint Mar 24 '20 at 17:36
  • Greetings, Thanks again for this control it worked perfectly in Visual Studio 2015. However, now that I've moved over to Visual Studio 2019 the control seems to disappear at times. That's right, at first it was there working perfectly. Then suddenly, the control disappear then obviously the form design is lost until I fix that problem. It's a confusing problem because I have no idea why it suddenly disappears. Any thoughts on that? – DemarcPoint Dec 01 '20 at 15:42
0

We can keep it simple and use the validating event:

    this.txtTracerouteIP.Validating += this.txtTracerouteIP_Validating;

And then:

    string pattern = @"^\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b$";

    private void txtTracerouteIP_Validating(object sender, CancelEventArgs e)
    {
        if (!Regex.IsMatch(txtTracerouteIP.Text, pattern))
        {
            MessageBox.Show("IP Address must be in the format '255.255.255.255'!");
            txtTracerouteIP.SelectAll();
            e.Cancel = true;
        }
    }
rfmodulator
  • 3,638
  • 3
  • 18
  • 22
  • 1
    That's pretty nice rfmodulator. Thank you for the reply. However, although the validation looks good. Is there a way to restrict the textbox to three dots only as used in IPv4? – DemarcPoint Mar 19 '20 at 23:28
  • @DemarcPoint I didn't confirm your regex was correct, I just copy and pasted it. I've fixed it to validate exactly 3 dots – rfmodulator Mar 19 '20 at 23:55
  • @DemarcPoint If you want to limit the input characters as well, continue to use your `KeyPress` handler in conjunction with this `Validating` handler. There is also a `IPAddress.TryParse()` method available, I just used regex because that's what you used. – rfmodulator Mar 20 '20 at 00:04
  • 1
    Yes, thank you. I'm also using "bool ValidateIP = IPAddress.TryParse(txtTracerouteIP.Text, out ip);. – DemarcPoint Mar 20 '20 at 00:06