How to insist that a textbox has a value - c#

I have a textbox on a form and a button on the same form. On the button click event I want to insist that the textbox has a value in the form of a Double. What I have so far is this -
public double getUnitStake(Form frontpage)
{
double doubleresult=0;
bool unitStake;
foreach (Control c in frontpage.Controls)
{
if (c.Name == "tbUnitStake")
{
unitStake = double.TryParse( (c as TextBox).Text, out doubleresult);
if (!unitStake)
{
}
else
{
doubleresult=double.Parse((c as TextBox).Text);
}
}
}
return doubleresult;
}
But for the life of me I can't figure out what to do if the double.tryparse method is false. What I want is the program execution to halt until a suitable value has been entered into the textbox. How can I achieve that please? Thanks for all and any help.

It seems to me you are validating the contents of a textbox. Therefore you can use the validating event of a TextBox Control. Optionally connect an errorProvider control to it to give special focus on the error (blinking exclamation mark). The "e.Cancel" statement will prevent you from doing anything else with your form until a double is entered.
private void textBox1_Validating(object sender, CancelEventArgs e)
{
double doubleresult = 0;
bool result = Double.TryParse(textBox1.Text, out doubleresult);
if (result)
{
errorProvider1.SetError(textBox1, string.Empty);
}
else
{
errorProvider1.SetError(textBox1, "Must be a Double");
e.Cancel = true;
}
}

I am not aware of the complete requirements of your program.
You could disable the button by default. In the text change event of the text box, check if the value entered is a double.
Once you have verified that the value is indeed a double, then you could enable the button.
This way the program execution is halted by default, unless a double is entered.

Your code is fine except the following change
public double getUnitStake(Form frontpage)
{
double doubleresult=0;
bool unitStake;
foreach (Control c in frontpage.Controls)
{
if (c.Name == "tbUnitStake")
{
unitStake = double.TryParse( (c as TextBox).Text, out doubleresult);
}
}
return doubleresult;
}
you need not to parse the "doubleresult" again as the tryparse has already done it. You can use unitStake variable for further use.

you just need TryParse yor value if your value not a double this method return you 0.0:
public double getUnitStake(Form frontpage)
{
double doubleresult=0;
foreach (Control c in frontpage.Controls)
{
if (c.Name == "tbUnitStake")
{
double.TryParse( (c as TextBox).Text, out doubleresult);
}
}
return doubleresult;
}

Related

Why is a string working in MessageBox but not in the if statement

WebClient wc = new WebClient();
string code = wc.DownloadString("link");
MessageBox.Show(code); // CODE SHOWS IN MESSAGEBOX CORRECTLY.
if (textbox.Text == code)
{
MessageBox.Show("Key Approved!");
try
{
Form1 Form1 = new Form1();
Form1.Show();
this.Hide();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
else
{
MessageBox.Show("This Key is incorrect.");
}
The text inside the Textbox is the Text in the code string, although textbox.Text == code is false and it returns to the else argument.
Any idea why this is happening?
Text inside the Textbox is the Text in the code string, although textbox.Text == code is false and it returns to the else argument.
I don't believe you. And since you failed to show evidence for this, I'm convinced you are wrong.
This suggests that TextBox.Text is not identical to code. If they look the same, then the difference is probably something like extra spaces, upper vs. lower case, or other minor differences.
The only other imaginable cause is that you've overridden the string equality operator somehow to do something unexpected.
Try this code instead:
Test(TextBox.Text, code);
void Test(string textbox, string code)
{
if (textbox.Length != code.Length)
{
MessageBox.Show("Strings are different lengths!");
return;
}
for (int i = 0; i < textbox.Length; i++)
{
if (textbox[i] != code[i])
{
MessageBox.Show(string.Format("'{0}' does not equal '{1}'", textbox[i], code[i]));
return;
}
}
MessageBox.Show("Strings are identical!");
}
Why not use .equals() instead of == when comparing strings

Using Linq to loop through all controls only get the first control

I have a form with 5 text boxes and a button, I want to check all these text boxes for empty or null user input.
Using this simple method:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (verifyUI() == true)
MessageBox.Show("user input for all textboxes was correct!");
else
MessageBox.Show("user input for all textboxes was missing!");
}
private bool verifyUI()
{
bool userInputOk = false;
foreach (Control cTxt in Controls.OfType<TextBox>())
{
if (string.IsNullOrWhiteSpace(cTxt.Text) || cTxt.Text == "")
{
userInputOk = false;
}
else
{
userInputOk = true;
}
}
return userInputOk;
}
}
When I enter a value in text box 1 , the method is checking only the first text box and returning true, and ignoring all other text boxes.
I am sure something is wrong in the logic of the method which I am using.
It seems you want to know if any input is wrong (or all the input is correct):
private bool verifyUI() {
return !Controls
.OfType<TextBox>()
.Any(cTxt => string.IsNullOrWhiteSpace(cTxt.Text));
}
or (equivalent All() implementation)
private bool verifyUI() {
return Controls
.OfType<TextBox>()
.All(cTxt => !string.IsNullOrWhiteSpace(cTxt.Text));
}
In your current code you constantly re-write userInputOk and so return the last value
The easiest way would be to use the All method:
private bool verifyUI()
{
return Controls.OfType<TextBox>().All(tb => !string.IsNullOrWhiteSpace(tb.Text));
}
You could also invert the logic and use the Any method as well. I prefer All in this case simply because it conveys the intention better and makes the logic more clear for the next person.
I think just for checking whether any textbox is not filled. following code is enough.
private bool verifyUI()
{
bool alluserInputsOk = true;
foreach (Control cTxt in Controls.OfType<TextBox>())
{
if (string.IsNullOrWhiteSpace(cTxt.Text))
{
userInputOk = false;
break;
}
}
return userInputOk;
}
or You can use .any() method with your list
Your code is actually only checking whether the last control in the list is blank or not, since that's where your iteration ends.
Your code checks only the last textbox it finds. Try this All() statement instead:
bool userInputOk = Controls.OfType<TextBox>()
.All(tb => !string.IsNullOrWhiteSpace(tb.Text));
Note that string.IsNullOrWhiteSpace() is true for string.Empty, too. So you don't need that extra check for string.Empty.
Actually, it's probably looping though all controls, but only returning the result of the last one, since you set the value of userInputOk back to true if the control has valid text. So the end result is the result for the last control. Now it's possible that textBox1 is the last control in the collection, depending on how they were added. You can either just remove the else block, which will flag userInputOk only if a control has an invalid value, or use Linq:
bool userInputOk =
!Controls.OfType<TextBox>()
.Any(cTxt => string.IsNullOrWhiteSpace(cTxt.Text))

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.

Calling ErrorProvider.Dispose does not clear the error text every time

I have a Windows Forms application and am calling ErrorProvider.Dispose to clear the error text. However, when I call it a second time it does not work (i.e. if a textbox is empty the ErrorProvider will show but after I filled the textbox and pressed the submit button again, it won't show the error).
I have a form with many textboxes and Im just checking if the fields are empty or not after clicking the submit button:
foreach (Control c in this.college.Controls)
{
if (c is TextBox)
{
TextBox textBox = c as TextBox;
if (textBox.Text.Equals(string.Empty))
{
if (string.IsNullOrWhiteSpace(textBox.Text))
{
errorProvider1.SetError(textBox, "Field Empty");
}
else
{
errorProvider1.Dispose();
}
}
}
}
If your intention is only to clear the previous error message then simply call again the SetError method but pass in an empty string.
if (string.IsNullOrWhiteSpace(textBox.Text))
{
errorProvider1.SetError(textBox, "Field Empty");
}
else
{
errorProvider1.SetError(textBox, string.Empty);
}
There is no need to call Dispose(). Rather, calling Dispose will destroy the errorprovider and it will be unusable for the rest of the lifetime of your form.
I would think that your code never reaches the line with
errorProvider1.Dispose()
since the if-statement
if (textBox.Text.Equals(string.Empty))
make the second if-statement
if (string.IsNullOrWhiteSpace(textBox.Text))
useless.
If textBox.Text is empty, then it is also null-or-whitespace.
You don't want to call .Dispose() on the error provider - this will be automatically collected by the garbage collection. Your code should probably look like the following:
foreach (Control c in this.college.Controls)
{
if (c is TextBox)
{
TextBox textBox = c as TextBox;
if (string.IsNullOrWhiteSpace(textBox.Text))
{
errorProvider1.SetError(textBox, "Field Empty");
}
else
{
errorProvider1.SetError(textBox, "");
}
}
}

C# - Correct validation for integers

I am currently building my project using windows forms and came across a minor "problem".
I have the user enter an hour which is stored as an int. I want to provide detailed feedback to the user so that they know exactly what they have done wrong should they cause an error.
If no value is given, a format exception is thrown.
If anything but an integer is given, a format exception is thrown.
This means I cannot directly tell the user that the new item could not be added due to EITHER 1) no value or 2) not an integer as they both use the same exception.
How can I solve this and what would be the best solution?
Many thanks.
Use the Int32.TryParse Method and check return value. You can simply check for no value entered before calling TryParse.
Here's an example of usage from MSDN:
int number;
bool result = Int32.TryParse(value, out number);
if (result)
{
Console.WriteLine("Converted '{0}' to {1}.", value, number);
}
else
{
if (value == null) value = "";
Console.WriteLine("Attempted conversion of '{0}' failed.", value);
}
some example code related to your question; note ValidateData in particular:
// called from ok button click or similar event
private void Accept()
{
if (!ValidateData())
return;
SaveData();
DialogResult = DialogResult.Ok;
Dispose();
}
private bool ValidateData()
{
int val;
if (string.IsNullOrEmpty(mTextBox.Text))
return FailValidation("Value can not be empty.", mTextBox);
if (!int.TryParse(mTextBox.Text, out val))
return FailValidation("Value was not an integer.", mTextBox);
return true;
}
// do something with the value if you need
private void SaveData()
{
}
// post a message to the user, and highlight the problematic control
// always evaluates to false
private bool FailValidation(string pMessage, Control pControl)
{
if (pControl != null)
{
pControl.Focus();
TextBox textBox = pControl as TextBox;
if (textBox != null)
textBox.SelectAll();
}
AlertBox(pMessage);
return false;
}
// quick alert message method
private void AlertBox(string pMessage)
{
return MessageBox.Show
(
pMessage,
Application.ProductName,
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation,
MessageBoxDefaultButton.Button1
);
}
Use int.TryParse to check format and than in success case check if integer is in valid range. Use String.IsNulOrEmpty to check for empty string.
If I can suggest a possible alternate solution... The best validation is preventing the bad input in the first place. Can you restrict the values the user can choose by using a control like a time picker or dropdown list? A dropdown list would still be keyboard friendly for powerusers, and it is a little easier for those who prefer a mouse. Wins for everyone.
This is well supported in Winforms. Use the Validating event to check the entry, the ErrorProvider component to report the error. A sample event handler:
private void textBox1_Validating(object sender, CancelEventArgs e) {
int hour;
e.Cancel = true;
if (textBox1.Text.Length == 0) errorProvider1.SetError(textBox1, "Can't be empty");
else if (!int.TryParse(textBox1.Text, out hour)) errorProvider1.SetError(textBox1, "Not a number");
else if (hour < 1) errorProvider1.SetError(textBox1, "Hour too small");
else if (hour > 24) errorProvider1.SetError(textBox1, "Hour too large");
else {
e.Cancel = false;
errorProvider1.SetError(textBox1, "");
}
}
Then you just need to check if all entries were satisfactory. Use the ValidateChildren() method in the dialog's OK button click event handler:
private void OKButton_Click(object sender, EventArgs e) {
if (ValidateChildren()) this.DialogResult = DialogResult.OK;
}

Categories

Resources