C# textBox Hex only with 0x/h/$ prefix using TextChanged property

1.4k Views Asked by At

I am testing the following code in TextChanged property to allow only HEX values in the textBox and it works just fine, it also deletes pasted string which doesn't match the HEX pattern and converts the lower to upper case, this is just what I needed:

Regex nonhex = new Regex("[^0-9,a-f,A-F]");
int caret = textBox1.SelectionStart - textBox1.Text.Length;
textBox1.Text = nonhex.Replace(textBox1.Text, "").ToUpper();
textBox1.SelectionStart = caret + textBox1.Text.Length;

If I try to add a prefix, the above code simply deletes it. What is the best way to modify the code in order to allow adding a permanent prefix (sth like 0x, h, $) such that I only use regular Expressions and TextChnaged property, is it possible anyway? I also need to be able to specify the max length of the HEX value, for example 4 digits for a PID and VID HID device, because I might use it in some different project which will need more or less hex digits..

I looked in the forum for a similar solution, but most people use more than one event and barely achieve what these four lines can do. Using RegEx is not a border-line crime BTW..

thanks

1

There are 1 best solutions below

0
On

What you're doing with those four lines is you're combining validation and correction, which is difficult at best and in many cases impossible. If you really want to do this, you'll first have to validate the input. Only if it's invalid should you modify it.

I would suggest that you create a regular expression that will first validate, like this:

Regex validInput = new Regex(@"^(\$|h|0x)?[0-9a-f]*", RegexOptions.IgnoreCase);
if (validInput.IsMatch(textBox1.Text))
{
    return;
}

If you get past that point, then you know that the text is bad in some way. If you want to correct it, you'll have to determine where it's bad. And you're not going to do that with a single regular expression. You have to determine if there is a valid prefix. If there is a valid prefix, then you can check the rest of the text to see if it's a valid hexadecimal number. If there is not a valid prefix, then you check the entire field to see if it's a valid number.

And after you've determined where the error is, you then have to fix it. That's difficult even in the simple case you describe.

I think you're going about this in totally the wrong way.

There are basically three ways to handle validation:

  1. Let the user enter any text he wants. You flag it as bad, but you leave it the way it is and let the user change it.
  2. Prevent the user from entering characters that aren't allowed. For example, only let him enter digits in a number entry field.
  3. Automatically correct the text when the user enters bad data.

You've picked #3, which is typically the most difficult (as I've described above) and, in my opinion as a user, the most annoying possible option.

You run into all kinds of problems. For example, say the user has entered "01AB", and then he goes back to the beginning and types "x", giving "x01AB". But you don't like that. You want "0x01AB", so you delete the "x" from the string. The user thinks, "Huh. I thought I pressed 'x'." So he tries it again. It'll take two or three tries before he figures out that your code so "helpfully" prevented him from entering bad data. As a user, I find that incredibly annoying and whenever I run into it I want to find the programmer who wrote it and lock him up so he can't perpetrate such ugliness ever again.

Over the years, I've found the first option to be the easiest to code and, as a user, the easiest to work with. If the user enters bad data, you can easily validate it and inform the user that he's made a mistake: typically by changing the border around the input box, placing an error indicator next to it, and possibly displaying some text that says why the input is bad and how to correct it. Using my example from above:

Regex validInput = new Regex(@"^(\$|h|0x)?[0-9a-f]*", RegexOptions.IgnoreCase);
if (validInput.IsMatch(textBox1.Text))
{
    // input is good. Clear errors.
    return;
}
// Input is bad. Show error indicator.

Now, if the user presses the Ok or Save button, or whatever, and there's still bad data, you have to catch that and act accordingly (i.e. don't let the program proceed with bad data). But that's a whole lot easier than trying to correct what the user typed, and it's a whole lot less annoying, too.