How do I validate text entry to include only numbers? - c#

I want to obligate the person who is using my program to enter only numbers in the text label in c#. How can i do that?
example :
number of equations : (he should only enter a number)
This code to obligate him to enter a number between 2 and 10 but i need a code for letters
if (int.Parse(txt1.Text) < 2 || int.Parse(txt1.Text) > 10)
{
l6.ForeColor = System.Drawing.Color.Red;
l6.Text = "Svp choisir un nombre entre 2 et 10 ... Soyez Logique!";
}

put this (or a variation of this, according to what you want to let the user to enter) in the textbox keypress event, so basically you will manage key presses in this textbox..
Add System.Media library to use the beep if the user enters wrong key, or remove it from the code...
if ((e.KeyChar >= '0') && (e.KeyChar <= '9') && (txt1.Text.Length < 10))
{
}
else if (e.KeyChar == 0x08)
{
//BACKSPACE CHAR
}
else if (txt1.SelectionLength > 0)
{
//IF TEXT SELECTED -> LET IT OVERRIDE
}
else
{
e.Handled = true;
SystemSounds.Beep.Play();
}

if (txt1.Text.Trim().Length > 0)
{
// Parse the value only once as it can be quite performance expensive.
Int32 value = Int32.Parse(txt1.Text)
if ((value >= 2) && (value <= 10))
{
l6.ForeColor = Color.Red;
l6.Text = "Svp choisir un nombre entre 2 et 10 ... Soyez Logique!";
// Clear the text...
txt1.Text = "";
}
else
{
// Your code here...
}
}
But, IMHO, TryParse is even better as it can handle bad string formats in a better way:
if (txt1.Text.Trim().Length > 0)
{
Int32 value;
if (!Int32.TryParse(txt1.Text, out value))
{
l6.ForeColor = Color.Red;
l6.Text = "Svp choisir un nombre entre 2 et 10 ... Soyez Logique!";
// Clear the text...
txt1.Text = "";
}
else
{
// Your code here...
}
}

What GUI do you use?
Using Winforms there are two ways that come to mind:
I recommend: Use a numericUpDown Control instead of a textBox. This way the user can only enter numbers and has nice Up/Down arrows to change the value. Plus you get handling of cursor keys.
Implement an Validating event handler.

Checking the various methods to insert text in a textbox to avoid non number chars is not an easy task and more often than not it fails somewhere. For example what about text pasted from the clipboard?, what about Backspace, Delete, Left, Right arrows keys?.
In my opinion it is better to follow a different approach.
Use the Validating event and let the user type or paste whatever he wants. At the validation event do you checks and advise the user or add a special errorProvider to signal the error:
private void l6_Validating(object sender, CancelEventArgs e)
{
int isNumber = 0;
if (l6.Text.Trim().Length > 0)
{
if (!int.TryParse(l6.Text, out isNumber))
{
e.Cancel = true;
errorProvider1.SetError(l6, "Svp choisir un nombre entre 2 et 10 ...";);
}
else
{
errorProvider1.SetError(l6, "");
}
}
}
}

Related

How to clear the first key press immediately after the short dialog box,if it is a wrong entry in a text box

I'm checking the user ID in the text box. And it can not start with a letter or digit '0'. I can catch the wrong entry and send a message to the screen. But the wrong entry will be in the text box until I hit another key. And if this is an acceptable digit then the wrong entry stays at the beginning of the string. So I need to get rid of the wrong entry immediately after the message dialog box. Any suggestion?
private void TxtUserID_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar))
{
MessageBox.Show(" Your User ID can not begin with a letter !!!");
//txtUserID.Text = string.Empty;
txtUserID.Clear();
}
else if (e.KeyChar == '0')
{
MessageBox.Show("Your User ID can not begin with 0 !!!");
txtUserID.Text = string.Empty;
}
}// end of keypress
I suggest using TextChanged instead of KeyPress event: whatever changed TxtUserID.Text (e.g. Paste, or, imagine, user put "12340" and then deleted "1234" in order to obtain "0") validate the TxtUserID
private static bool IsNameValid(string name) {
if (string.IsNullOrEmpty(name))
return true;
else if (name.Any(c => c < '0' || c > '9')) {
MessageBox.Show("Your User ID must contain digits only!");
return false;
}
else if (name.StartsWith("0")) {
MessageBox.Show("Your User ID must not start from 0!");
return false;
}
return true;
}
private void TxtUserID_TextChanged(object sender, EventArgs e) {
if (!IsNameValid(TxtUserID.Text))
txtUserID.Clear(); // Taken from the question
}
Edit: As Thomas Voß pointed out, clearing the entire text can be to cruel for a user (imagine that he's printed "1001234566978563" and then decided to remove leading "100"), probably
txtUserID.Text = string.Concat(txtUserID
.Text
.Where(c => c >= '0' && c <= '9') // Digits only
.SkipWhile(c => c == '0')); // Trim all starting '0'
instead of txtUserID.Clear(); when we remove all characters but digits and trim leadibng 0 is a better choice.

Positioning the counter, More logic than coding

I am trying to make the users to select a maximum of 4 toppings. Pressing a button they will change the color of the button and add it to a list which will be displayed.Also, the user can delete the topping by pressing again on the same button. I managed to get all of these sorted, the problem is that when the user adds the last topping and the program does not allow him to delete it anymore. I was changing constantly the position of the if statement or the counter but nothing. I presume is a logic problem however I could not find it. Please give me a hand
private void labelTuna_Click(object sender, EventArgs e)
{
if (counter < 4)
{
if (!My_Pizza.Items.Contains(tuna))
{
My_Pizza.Items.Add(tuna);
labelTuna.BackColor = Color.Green;
counter++;
}
else
{
My_Pizza.Items.Remove(tuna);
labelTuna.BackColor = Color.LightSteelBlue;
counter--;
}
}
else
{
MessageBox.Show("You have more than 4 toppings, Remove then replace one");
}
If you want just make your code work this will do.
if ( counter >= 4 && !My_Pizza.Items.Contains(tuna) )
{
MessageBox.Show("You have more than 4 toppings, Remove then replace one");
{
else
{
if (!My_Pizza.Items.Contains(tuna))
{
My_Pizza.Items.Add(tuna);
labelTuna.BackColor = Color.Green;
counter++;
}
else
{
My_Pizza.Items.Remove(tuna);
labelTuna.BackColor = Color.LightSteelBlue;
counter--;
}
}
Your error was not to check if one of the topping preset was the tuna.
Having said that the code is a bit messy even.
You don't need the counter variable, just check My_Pizza.Items.Count
And also as you have written the program you need to write almost duplicate code for each topping.
A function with a parameter will be better.

Position cursor on textbox that has error

I have a simple form that takes 9 decimal numbers from 9 textboxes and I put some validation so that the users can only enter decimal numbers and nothing else.
Now the challenge I'm having is how to set the cursor in the textbox that had no decimal number after showing the error message in the try-catch statement?
Here's my code:
private void btn_Aceptar_Click(object sender, EventArgs e)
{
POI GPI = new POI();
POI VIM = new POI();
POI ST = new POI();
try
{
GPI.POI_x = Convert.ToDecimal(txt_GPIx.Text);
GPI.POI_y = Convert.ToDecimal(txt_GPIy.Text);
GPI.POI_z = Convert.ToDecimal(txt_GPIz.Text);
VIM.POI_x = Convert.ToDecimal(txt_VIMx.Text);
VIM.POI_y = Convert.ToDecimal(txt_VIMy.Text);
VIM.POI_z = Convert.ToDecimal(txt_VIMz.Text);
ST.POI_x = Convert.ToDecimal(txt_STx.Text);
ST.POI_y = Convert.ToDecimal(txt_STy.Text);
ST.POI_z = Convert.ToDecimal(txt_STz.Text);
}
catch (Exception)
{
MessageBox.Show("Ingrese solamente números en las variables GPI/VIM/ST", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
//Set the cursor in the first textbox that had no decimals..
return;
}
Comisurales Comisurales = new Comisurales();
Comisurales.calculo_coord_comisurales(PC, AC, IHP, GPI, VIM, ST);
}
Let me add that I also have a function to ensure the user is only limited to enter decimals but I wasn't able to figure how to avoid the "." only or this for example: "1."
As an addition to my question, here's what gets validated every time the user press a key in the textbox:
private void ValidarDecimal(object sender, KeyPressEventArgs e)
{
// permitir 0-9, backspace, y decimal
if (((e.KeyChar < 48 || e.KeyChar > 57) && e.KeyChar != 8 && e.KeyChar != 46))
{
e.Handled = true;
return;
}
// chequear solamente un decimal
if (e.KeyChar == 46)
{
if ((sender as TextBox).Text.IndexOf(e.KeyChar) != -1)
e.Handled = true;
}
}
I guess I have 2 ways to resolve my issue. Number one would be find a way to ensure the user never ever enters something weird in the textbox (which I've done partially) and number 2 would be to use the try-catch with the current limitations I mentioned above and then point the user to the textbox that has issues, both are acceptable.
The Decimal class has a TryParse method that could be used to avoid all this logic driven by catching exceptions (a very expensive approach in terms of performance)
decimal value;
if(decimal.TryParse(txt_GPIx.Text, out value))
GPI.POI_x = value;
else
{
MessageBox.Show("Invalid decimal value");
txt_GPIx.Focus();
}
Of course this code needs to be repeated for every control in your list, but you could write a generic function like this one
private decimal GetValueAndValidate(Textbox txt, out bool isOK)
{
isOK = true;
decimal value = 0m;
if(!decimal.TryParse(txt.Text, out value))
{
MessageBox.Show("Invalid decimal value");
txt.Focus();
isOK = false;
}
return value;
}
and then use the following approach in your code inside the button click
bool isOK = true;
if(isOK) GPI.POI_x = GetValueAndValidate(txt_GPIx, out isOK);
if(isOK) GPI.POI_y = GetValueAndValidate(txt_GPIy, out isOK);
.... and so on for the other fields ....
For the second part of your question, finding a way to completely control the input logic is not easy. What happens for example if your user PASTE an invalid text in your textbox? There are very edge case situations that takes a lot of effort to code correctly. It is a lot more easy to leave freedom of typing to your user and apply a strict logic when you get that input.

C# WinForm + Barcode Scanner input, TextChanged Error

UPDATE: SOLUTION AT END
I have a Winform, label1 will display some info returned from a SQL Search using the input (MemberID) received from barcode scanner via txtBoxCatchScanner.
Scenario is people swiping their MemberID Cards under the scanner as they pass through reception and the Winform automatically doing a Search on that MemberID and returning their info including for example "Expired Membership" etc on the receptionist's PC which has the winForm in a corner of her desktop.
I have the Below Code working fine on first swipe (eg. first person)
The number MemberID, for example 00888 comes up in the text box, ADO.NET pulls the data from SQL and displays it fine.
one thing to note maybe, the cursor is at the end of the memberID: 00888|
All good so far, THEN:
when swipe 2 (eg. next person) happens
their number (say, 00999) gets put onto the end of the first in the txtBox eg: 0088800999 so naturally when TextChanged Fires it searches for 0088800999 instead of 00999 ....
I've tried:
txtBoxCatchScanner.Clear();
and
txtBoxCatchScanner.Text = "";
and
reloading the form
at the end of my code to "refresh" the text box
but i guess they trigger the TextChanged Event
How can i refocus or ... clear the old number and cursor back to start of txtBox after the previous swipe has done its stuff...
I'm a beginner so I'm sure the code below is pretty crap....
But if anyone has time, please let me know how fix it to do what i want.
UPDATE:
Ok after much experimenting I''ve managed to get this 1/2 working now hopefully someone more experience can help me to completion! :P
if (txtBoxCatchScanner.Text.Length == 5)
{
label1.Text = txtBoxCatchScanner.Text; // just a label for testing .. shows the memmber ID
txtBoxCatchScanner.Select(0, 5);
}
SO scan 1, say 00888 , then that gets highlighted, scan 2 , say 00997 ... sweet! overwrites (not appends to) 00888 and does it's thing ... scan 2 0011289 ... DOH!!
Problem: not all barcodes are 5 digits!! they are random lengths!! Memeber ID range from 2 digit (eg. 25) to 10 digits, and would grow in the future...
Edit: Something I've discovered that is that the barcodes are read as indvidual key presses. I think this is why answer 1 below does not work and while the big probmlems:
for example with 00675 the input (?output) from the scanner is:
Down: Do
Up: Do
Down: Do
Up: Do
Down: D6
Up: D6
Down: D7
Up: D7
Down: D5
Up: D5
down: Retunn
Up: Return
other info: barcode scanner is: an Opticon OPL6845 USB
Thanks
private void txtBoxCatchScanner_TextChanged(object sender, EventArgs e)
{
Member member = new Member();
member.FirstName = "";
member.LastName = "";
//Get BarCode
//VALIDATE: Is a Number
double numTest = 0;
if (Double.TryParse(txtBoxCatchScanner.Text, out numTest))
{
//IS A NUMBER
member.MemberID = Convert.ToInt32(txtBoxCatchScanner.Text);
//SEARCH
//Search Member by MemberID (barcode)
List<Member> searchMembers = Search.SearchForMember(member);
if (searchMembers.Count == 0)
{
lblAlert.Text = "No Member Found";
}
else
{
foreach (Member mem in searchMembers)
{
lblMemberStatus.Text = mem.MemberStatus;
lblMemberName.Text = mem.FirstName + " " + mem.LastName;
lblMemberID.Text = mem.MemberID.ToString();
lblMessages.Text = mem.Notes;
if (mem.MemberStatus == "OVERDUE") // OR .. OR .. OR ...
{
lblAlert.Visible = true;
lblAlert.Text = "!! OVERDUE !!";
//PLAY SIREN aLERT SOUND
//C:\\WORKTEMP\\siren.wav
SoundPlayer simpleSound =
new SoundPlayer(#"C:\\WORKTEMP\\siren.wav");
simpleSound.Play();
}
else
{
lblAlert.Visible = true;
lblAlert.Text = mem.MemberStatus;
}
}
}
}
else
{
//IS NOT A NUMBER
lblAlert.Text = "INVALID - NOT A NUMBER";
////
//lblMemberName.Text = "";
//lblMemberID.Text = "";
//lblMemberID.Text = "";
}
SOLUTION:
The System won't let me answer my own question for another 3 hours, as I'm a newbie only 1 post, so will put here:
First thanks everyone for your help and Patience.
I Have finally figured a solition, not fully tested yet as its 2am and bed time.
following along from my updates where I had success but hit the variable length of MemberID problem. I've now overcome that with the Code below:
namespace SCAN_TESTING
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void txtBoxCatchScanner_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyValue == (char)Keys.Return)
{
e.Handled = true;
int barcodeLength = txtBoxCatchScanner.TextLength;
txtBoxCatchScanner.Select(0, barcodeLength);
//TEST
label3.Text = barcodeLength.ToString();
//TEST
label2.Text = txtBoxCatchScanner.Text;
}
}
I'll add this to my previous "real" code and test in the morning
But at this stage is doing exactly what I want! =]
Update: Tested it .. works exactly what needed:
private void txtBoxCatchScanner_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyValue == (char)Keys.Return)
{
e.Handled = true;
int barcodeLength = txtBoxCatchScanner.TextLength;
txtBoxCatchScanner.Select(0, barcodeLength);
//
//INSERT ORGINAL CODE HERE. No Changes were needed.
//
}//end of if e.KeyValue ...
}//end txtBoxCatchScanner_KeyUp
Hope that helps anyone in the future!! :)
Thanks again for the 2 very good solutions, I can see how they work, and learnt alot.
Just didn't work in my case - more likely due to myself or my error/not understanding, or scanner type.
I´m not exactly sure what the actual problem is.
txtBoxCatchScanner.Clear();
txtBoxCatchScanner.Text = "";
both trigger the "Changed" Event.
But they also clear the box. So that should be what you want to do.
You could check at the beginning if the box is actually empty, and return in case it is. Like:
if(txtBoxCatchScanner.Text == "" |txtBoxCatchScanner.Text == string.Empty)
return;
So nothing else happens, if the box is empty.
If I misunderstood your problem, please specify and I will try to help.
Regards
EDIT:
Your function should work if it looked something like this:
private void txtBoxCatchScanner_TextChanged(object sender, EventArgs e)
{
Member member = new Member();
member.FirstName = "";
member.LastName = "";
if(txtBoxCatchScanner.Text == "" | txtBoxCatchScanner.Text == string.Empty)
return; // Leave function if the box is empty
//Get BarCode
//VALIDATE: Is a Number
int numTest = 0;
if (int.TryParse(txtBoxCatchScanner.Text, out numTest))
{
//IS A NUMBER
//member.MemberID = Convert.ToInt32(txtBoxCatchScanner.Text);
member.MemberID = numTest; // you already converted to a number...
//SEARCH
//Search Member by MemberID (barcode)
List<Member> searchMembers = Search.SearchForMember(member);
if (searchMembers.Count == 0)
{
lblAlert.Text = "No Member Found";
}
else
{
foreach (Member mem in searchMembers)
{
lblMemberStatus.Text = mem.MemberStatus;
lblMemberName.Text = mem.FirstName + " " + mem.LastName;
lblMemberID.Text = mem.MemberID.ToString();
lblMessages.Text = mem.Notes;
if (mem.MemberStatus == "OVERDUE") // OR .. OR .. OR ...
{
lblAlert.Visible = true;
lblAlert.Text = "!! OVERDUE !!";
//PLAY SIREN aLERT SOUND
//C:\\WORKTEMP\\siren.wav
SoundPlayer simpleSound =
new SoundPlayer(#"C:\\WORKTEMP\\siren.wav");
simpleSound.Play();
}
else
{
lblAlert.Visible = true;
lblAlert.Text = mem.MemberStatus;
}
}
}
}
else
{
//IS NOT A NUMBER
lblAlert.Text = "INVALID - NOT A NUMBER";
////
//lblMemberName.Text = "";
//lblMemberID.Text = "";
//lblMemberID.Text = "";
}
txtBoxCatchScanner.Clear();
}
The barcode scanner you use seems to function as a HID - a keyboard emulation. Every simple barcode scanner I know (and I'm working with them on a daily basis) has the option of specifying a suffix for the scanned barcode. Change the suffix to CRLF and add a default button to your form. Scanning a barcode that ends with CRLF will then automatically "push the button".
Move the code that performs the checks from TextChanged event in to the event handler for the buttons Click event and remove the TextChanged event handler. Then, when the button is clicked, also clear the text box and set the focus back to the text box.
You should be good to go, now.
You can easily check whether the barcode scanner already has the correct suffix configured: Open up Notepad and scan some barcodes. If they all appear on separate lines, then everything's fine. Otherwise you'll need to scan some configuration barcodes from the scanner's manual.
To sum it all up, this should be the code for the button's Click event:
private void btnCheckMember_Click(object sender, EventArgs e)
{
Member member = new Member();
member.FirstName = "";
member.LastName = "";
string memberText = txtBoxCatchScanner.Text.Trim();
txtBoxCatchScanner.Text = String.Empty;
int numTest = 0;
if (String.IsNullOrEmpty(memberText) ||!Int32.TryParse(memberText, out numTest))
{
//IS NOT A NUMBER
lblAlert.Text = "INVALID - NOT A NUMBER";
return;
}
member.MemberID = numTest;
List<Member> searchMembers = Search.SearchForMember(member);
if (searchMembers.Count == 0)
{
lblAlert.Text = "No Member Found";
}
else
{
foreach (Member mem in searchMembers)
{
lblMemberStatus.Text = mem.MemberStatus;
lblMemberName.Text = mem.FirstName + " " + mem.LastName;
lblMemberID.Text = mem.MemberID.ToString();
lblMessages.Text = mem.Notes;
if (mem.MemberStatus == "OVERDUE") // OR .. OR .. OR ...
{
lblAlert.Visible = true;
lblAlert.Text = "!! OVERDUE !!";
SoundPlayer simpleSound = new SoundPlayer(#"C:\\WORKTEMP\\siren.wav");
simpleSound.Play();
}
else
{
lblAlert.Visible = true;
lblAlert.Text = mem.MemberStatus;
}
}
}
This solution avoids the following problems:
The event being triggered upon every character added/removed from the content of the text box (which is also the case when scanning a barcode: They are added one by one as if they were entered on a keyboard)
Resulting from 1. the problem that a member check is performed upon every entered character
Resulting from 2. the problem that member XYZ will never be found if there is a member XY in the database, as the check stops after finding XY
Resulting from 3. the problem that member XY will also not be found, but only member Z, because in 3. the text box is cleared and Z is the only character being entered.
The best way to clear the textBox on the next textChange event.
Insert this line
txtBoxCatchScanner.SelectAll();
at the end of TextChange function.. This will select the text, so that i can be replaced easily on the next event.

Error message to show which text boxes are blank C#

Hey so I have all my code working and it's fine. But I'd like to clean it up a little.
At the moment I just have a message box show if there is an error in the input, so it would show "Please check your input", however I'd like it to show something like "Please check the following: firstname, secondname etc."
if ((FirstnameText.Text.Trim().Length == 0) || (SurnameText.Text.Trim().Length == 0)
|| (DateOfBirthText.Text.Trim().Length == 0) || (CourseText.Text.Trim().Length == 0)
|| (MatricNoText.Text.Trim().Length == 0) || (YearMarkText.Text.Trim().Length == 0)
|| (int.Parse(MatricNoText.Text) < 10000 || int.Parse(MatricNoText.Text) > 99999)
|| (int.Parse(YearMarkText.Text) < 0 || int.Parse(YearMarkText.Text) > 100))
{
errorMessage();
return;
}
public void errorMessage()
{
MessageBox.Show("Please check your input");
}
I know it's messy, but hey it works
Currently it just outputs that message, is there a simple way to output the specific textbox which has the error?
thanks
The built-in ErrorProvider component will work wonders for your situation. Drag it from the toolbox onto the designer for your form. It will appear at the bottom, where NotificationIcons and ContextMenuStrips appear. The great thing about the ErrorProvider is it give a visual feedback icon with a mouse over tooltip next to the control.
You can then use the "Validating" event of the control to check what you need:
private void FirstnameText_Validating (object sender, CancelEventArgs e)
{
string error = null;
if (FirstnameText.Text.Length == 0)
{
error = "You must enter a First Name";
e.Cancel = true; // This is important to keep focus in the box until the error is resolved.
}
ErrorProvider.SetError((Control)sender, error); // FirstnameText instead of sender to avoid unboxing the object if you care that much
}
You can also stick it in the Save button instead of raising it on the "Validating" event. To clean your code up even more, make a class that validates the input to keep non-UI stuff out of the UI.
Splitting up your code would be a start:
if ((FirstnameText.Text.Trim().Length == 0){
errorMessage("firstname is empty");
}
if (SurnameText.Text.Trim().Length == 0){
errorMessage("surname is empty");
}
Get the idea?
I often use Fluent Validation. The WithMessage method lets you specify an error message. The validator then returns you an enumerable of all error messages. There might also be a better fitting method for your specific problem.
If possible you re-write your code like below
Control errorControl =null;
foreach (Control ctrl in this.Controls)
{
if (ctrl is TextBox)
{
if (ctrl.Name == "MatricNoText")
{
if ((int.Parse(MatricNoText.Text) < 10000 || int.Parse(MatricNoText.Text) > 99999))
{
errorControl = ctrl;
}
}
else if (ctrl.Name == "MatricNoText")
{
if (int.Parse(YearMarkText.Text) < 0 || int.Parse(YearMarkText.Text) > 100)
{
errorControl = ctrl;
}
}
else
{
if (ctrl.Text.Length == 0)
{
errorControl = ctrl;
}
}
}
}
MessageBox.Show("Please check your input." + errorControl.Focus());

Categories

Resources