I have a save button. When a user clicks it. The data-input in the the form will be validated before it will be send to the db. How can I achieve it?
Here's the code of my save button.
private void save_Click(object sender, EventArgs e)
{
try
{
int civil_caseI = int.Parse(civil_case.Text);
}
catch (Exception cc)
{
MessageBox.Show("Enter Number Only on CIVIL CASE");
}
string areaI = area.Text;
if (areaI.Length <= 0)
{
MessageBox.Show("Area Field must not be Empty");
}
string addressI = address.Text;
if (addressI.Length <= 0)
{
MessageBox.Show("Address Field must not be Empty");
}
// HERE WILL BE THE QUERY TO INSERT THE DATA AFTER THE FORM IS VALIDATED.
}
You are not returning from your method if there is an error in validation. return early from your method if there is an exception/failure in rule validation. You can just add return; statement after showing the error message.
A better way would be to use int.TryParse to parse int values instead of try-catch. Remember exceptions are expensive. You can also use string.IsNullOrWhiteSpace instead of addressI.Length <= 0 which will consider white space as invalid values (if you are using .Net framework 4.0 or higher, otherwise use `string.IsNullOrEmpty).
private void save_Click(object sender, EventArgs e)
{
int civil_caseI;
if (!int.TryParse(civil_case.Text, out civil_caseI))
{
MessageBox.Show("Enter Number Only on CIVIL CASE");
return; //add that - early return
}
string areaI = area.Text;
if (string.IsNullOrEmpty(areaI.Trim()))
{
MessageBox.Show("Area Field must not be Empty");
return;
}
string addressI = address.Text;
if (string.IsNullOrEmpty(addressI.Trim())) //or addressI.Trim().Length <= 0
{
MessageBox.Show("Address Field must not be Empty");
return;
}
//HERE WILL BE THE QUERY TO INSERT THE DATA AFTER THE FORM IS VALIDATED.
}
You can also extract out the logic of your validation in a separate method returning bool and then call that method for validation.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
Edit add: The problem I was given amounts to making use of a text file that contains 18 differing account numbers. I'm given the option of making the program read it to an array or a List<>. Then the program should allow a user to input a number and determine if it matches an entity in the array/List<>, displaying that it's valid/invalid.
It took me a fair while to get my code to work correctly. Now, I don't mind that a bad input validation returning false is followed by the latter methods being run through, thus producing the second popup. It's rather annoying at times, however. It works fine, like I said, but I'd like to find out if there's a way to make it stop running through the rest if the validation returns false.
private void ReadAccNums(int[] accountNumArray)
{
// Try-catch to prevent file error issues.
try
{
// Increment num var.
int num = 0;
// Open ChargeAccounts.txt file.
StreamReader accNumsFile = File.OpenText("ChargeAccounts.txt");
// Read account numbers into array.
while (num < accountNumArray.Length && !accNumsFile.EndOfStream)
{
// Put each item into accountNumArray.
accountNumArray[num] = int.Parse(accNumsFile.ReadLine());
num++;
}
// Close file.
accNumsFile.Close();
}
catch (Exception ex)
{
// Display error message.
MessageBox.Show(ex.Message);
}
}
// Method to handle TextBox input
// validation.
private bool InputIsValid(ref int accNum)
{
// Flag to make sure input is good.
bool inputValid = false;
// Get and validate accountNumbersAccessTextBox input.
if (int.TryParse(accountNumberAccessTextBox.Text, out accNum))
{
// Did we get this far? Confirm input validation.
inputValid = true;
}
// Display error message for accNum.
else
{
MessageBox.Show("Please input a non-decimal, seven digit number" +
" for the account number.");
// Reset Focus to accountNumbersAccessTextBox.
accountNumberAccessTextBox.Focus();
}
// Return result.
return inputValid;
}
// Method to find out if input
// has a match in ChargeAccounts.txt.
private int AccNumSearch(int accNum,
int[] accountNumArray)
{
// Bool flag for matching accNum.
bool accNumFound = false;
// Index var.
int num = 0;
// Position of Sequential Search.
int position = -1;
// Get input from TextBox.
if (InputIsValid(ref accNum))
{
// Read through array to find
// matching accNum.
while (!accNumFound && num < accountNumArray.Length)
{
if (accountNumArray[num] == accNum)
{
// Found a match? Yay! Access granted!
accNumFound = true;
position = num;
}
num++;
}
}
// Return.
return position;
}
// Method to determine whether input
// matches an account number.
private bool AccNumMatch(int[] accountNumArray,
ref int accNum)
{
// Bool flag to confirm
// matching accNum.
bool accNumMatch = false;
// Got a match? Tell the user.
if (AccNumSearch(accNum, accountNumArray) != -1)
{
accNumMatch = true;
MessageBox.Show("Account number correct. Access granted.");
}
else
{
// No match? Alas.
MessageBox.Show("Account number invalid. Access denied.");
}
// Return.
return accNumMatch;
}
private void accountNumberAccessButton_Click(object sender, EventArgs e)
{
// Declare array to be filled by
// ReadAccNums method.
const int SIZE = 18;
int[] accountNumArray = new int[SIZE];
// Get the account numbers.
ReadAccNums(accountNumArray);
// Var for accNum to ref.
int accNum = 0;
// Is our account number correct?
AccNumMatch(accountNumArray, ref accNum);
}
Your code seems and incredibly verbose approach to:
the user types a number into a textbox
the program checks it's numeric
the program checks it's present in a file
If I was tasked to write such a code I might:
void Login_Click(object sender, EventArgs e){
if(!int.TryParse(accountNumberTextbox.Text, out int seeking)) {
MessageBox.Show("The account number text does not appear to be numeric");
return;
}
accNumMatch = File.ReadLines("c:\\temp\\accountnumbers.txt").Any(line => line == accountNumberTextbox.Text));
if(accNumMatch) {
MessageBox.Show("Account number correct. Access granted.");
}
else {
MessageBox.Show("Account number invalid. Access denied.");
}
}
because there simply isn't any point in converting the file contents to number and then searching the number; simpler to leave them as strings and compare strings, after making sure what the user entered was a number
And if I used a numericupdown so the user couldn't even enter a non number:
void Login_Click(object sender, EventArgs e){
accNumMatch = File.ReadLines("c:\\temp\\accountnumbers.txt").Any(line => line == accountNumberNumericUpDown.Value.ToString()));
if(accNumMatch) {
MessageBox.Show("Account number correct. Access granted.");
}
else {
MessageBox.Show("Account number invalid. Access denied.");
}
}
YOu can just convert what they entered to text and launch straight into reading the file and looking for a line bearing what they entered
I appreciate you might be learning, so using LINQ is a bit of a cheat, but even so:
void Login_Click(object sender, EventArgs e){
if(!int.TryParse(accountNumberTextbox.Text, out int seeking)) {
MessageBox.Show("The account number text does not appear to be numeric");
return;
}
accNumMatch = false;
StreamReader accNumsFile = File.OpenText("ChargeAccounts.txt");
while (!accNumsFile.EndOfStream && !accNumMatch)
{
string line = accNumsFile.ReadLine();
accNumMatch = (line == accountNumberTextbox.Text);
}
}
I'll forego lecturing about using/making sure you close and dispose your file readers etc for now ;)
If you have to read a file into an array, you can use System.IO.File.ReadAllLines() as a quick way to read a file. I won't use it here, but you can look it up if you want to see
If you have to read up to X lines from a file, into an array of ints, and then see if any of the ints are the one you seek:
void Login_Click(object sender, EventArgs e){
bool validInput = int.TryParse(accountNumberTextbox.Text, out int seeking);
if(!validInput) {
MessageBox.Show("The account number text does not appear to be numeric");
return;
}
int[] numbers = new int[100];
StreamReader accNumsFile = File.OpenText("ChargeAccounts.txt");
for(int i = 0; i < numbers.Length && !accNumsFile.EndOfStream; i++)
{
string line = accNumsFile.ReadLine();
numbers[i] = int.Parse(line);
}
accNumMatch = false;
foreach(int number in numbers){
if(number == seeking) { //seeking comes from earlier
accNumMatch = true;
break;
}
}
}
You could break these into separate methods. Make a method that takes an input and gives an output:
void Login_Click(object sender, EventArgs e){
int seek = ConvertToAccountNumber(accountNumberTextbox.Text);
if(seek == -1){
MessageBox.Show("Enter a valid number");
return
}
int[] numbers = GetAccountNumbersInFile("ChargeAccounts.txt");
accNumMatch = ArrayContainsNumber(numbers, seek);
}
//this is basically a variation of int.Parse/int.TryParse
public int ConvertToAccountNumber(string s){
bool validInput = int.TryParse(accountNumberTextbox.Text, out int seeking);
if(!validInput)
return -1; //we will use -1 to signify invalid input, because no account number is ever -1
else
return seeking;
}
//File.ReadAllLines can help with this, as can LINQ Select/int parse
public int[] GetAccountNumbersInFile(string p){
int[] numbers = new int[100];
StreamReader accNumsFile = File.OpenText(p);
for(int i = 0; i < numbers.Length && !accNumsFile.EndOfStream; i++)
{
string line = accNumsFile.ReadLine();
numbers[i] = int.Parse(line);
}
}
//there exist helper methods for doing this too, look at the Array class - https://learn.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1
public bool ArrayContainsNumber(int[] array, int seeking){
foreach(int number in numbers){
if(number == seeking) {
return true;
}
}
return false;
}
I know why you used ref but you should avoid it. Actually the framework uses out when it parses text to a number and returns a boolean to indiccate the success and a number, but you can easily take the approach that something like string.IndexOf takes - it returns -1 if the needle is not found in the haystack. You haven't learned about exceptions yet (probably) but this would be an opportunity to use them too - throw an exception instead of returning a value if the input data is bad
All in, it's one of the few places where out might be reasonable in your career, so use it if you must (for academicc reasons, but don't use ref - ref is for methods that take a variable in with the intention of using its value before possibly overwriting it with something else. This is an out scenario, where the input variable shouldn't have a value and will be overwritten by the method) but
I am creating a system that includes a ListBox of integers inserted by the user. I have contained a search button and a search TextBox for the user to input the integer they want to search for within the ListBox. Once the user has inputted the integer, I want a message box to be displayed either informing the user that there is e.g. 1 integer of value '3' in the list box, or an error message box informing the user that the integer does not exist within the list box.
private void buttonSearch_Click(object sender, EventArgs e)
{
listBoxAddedIntegers.SelectedItems.Clear();
for (int i = listBoxAddedIntegers.Items.Count - 1;i>=0; i--) ;
{
if (listBoxAddedIntegers.Items[i].ToString().ToLower().Contains(textBoxSearch.Text.ToLower())) ;
{
listBoxAddedIntegers.SetSelected(i, true);
}
}
// ...
}
I am not really sure on the code that I am meant to include here, and the code that I have already inserted suggests that 'i' does not exist in the current content.
Can anyone help please?
the code that I have already inserted suggests that 'i' does not exist in the current content
As #FrankM already mentioned in the comments. You have a trailing ; after your for-loop.
for (int i = listBoxAddedIntegers.Items.Count - 1;i>=0; i--) ;
This will prevent the for-loop to execute your code within the { ... }. This can be transcribed to
for (int i = listBoxAddedIntegers.Items.Count - 1;i>=0; i--)
{
// Do nothing.
}
{
// now your code
}
This means also that your code within the last curly braces will be in its own scope and so that all your defined variables will be unavailable to the following code.
Answering your actual question:
As you already do for selecting the matching items. You can extent this looping by counting up a counter. And later on show the results with a MessageBox.
With the following snippet of your code
listBoxAddedIntegers.Items[i].ToString().ToLower().Contains(textBoxSearch.Text.ToLower()))
you are currently checking if an item of your list contains the entered TextBox.Text.
So if the user has entered 3, 4, 5, ..., 13, 23 in the ListBox and searches for 3. He will get 3 matches. If you want only 1 match you should use String.Equals(). I used StringComparison.InvariantCultureIgnoreCase to avoid calling ToLower().
private void buttonSearch_Click(object sender, EventArgs e)
{
var counter = 0;
for (int i = 0; i < this.listBoxAddedIntegers.Items.Count; i++)
{
var item = this.listBoxAddedIntegers.Items[i];
if (string.Equals(item.ToString(), this.textBoxSearch.Text, StringComparison.InvariantCultureIgnoreCase))
{
this.listBoxAddedIntegers.SelectedItems.Add(item);
counter++;
}
}
if (counter == 0)
{
MessageBox.Show($"No matches for \"{this.textBoxSearch.Text}\" found!", "Search Results",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
MessageBox.Show($"{counter} items found for \"{this.textBoxSearch.Text}\"!", "Search Results",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
Hint:
Since C#6 you can use string interpolation instead of String.Format() or string concatenation (+).
private void buttonSearch_Click(object sender, EventArgs e)
{
listBoxAddedIntegers.SelectedItems.Clear();
var itemsFound = listBoxAddedIntegers.Items.Where(i=>i.ToString().ToLower().Contains(textBoxSearch.Text.ToLower())).ToList();
if(itemsFound == null)
{
MessageBox.Show("No matches found.");
}
else
{
MessageBox.Show("Found " + itemsFound.Count + " matches.");
}
}
You have to do this:
int count=0;
for(int i=0;i<listBoxAddedIntegers.Items.Count;i++)
{
if(listBoxAddedIntegers.Items[i].Items[i].ToString().ToLower().Contains(textBoxSearch.Text.ToLower())
{
count+=1;
}
}
if(count>0)
{
//display your message here after the loop with the count
}
else
{
//display your message with error
}
My problem is when the user clicks on myButton the program operates perfectly fine. But if the user was to input a value less than 3 in the first textbox a message box will appear to the user stating that the value must be greater than 3 metres. If you click OK the next method in myButton runs anyway and the result message box appears anyway.
I've tried looking around to solve this problem of mine using Nested For Loops but failed to get them to work (most likely a fault on my end). I also prefer not to use Goto because it isn't exactly good programming practice to use. Of course you can tell me otherwise if you want :) .
// Button
private void myButton_Click(object sender, EventArgs e)
{
checkIfNumericalValue();
testIfTextBoxOnesMinimumIsMet();
testIfTextBoxTwosMinimumIsMet();
displayResultToUser();
resetOrClose();
}
// Textbox One
public void testIfTextBoxOnesMinimumIsMet()
{
if (length < 3)
{
MessageBox.Show("length must be greater than 3 metres");
}
}
Help would be greatly appreciated this is also my second attempt at C# on Visual Studio 2012. Do not worry this has nothing to do with my year 10 schooling as my school doesn't have a programming subject. This problem occurs in testIfTextBoxOnesMinimumIsMet() and testIfTextBoxOnesMinimumIsMet() as well but if someone can help me with this one method I should be able to fix the rest :)
You could throw an exception from your inner functions and catch it from your button's function, something like this:
// Button
private void myButton_Click(object sender, EventArgs e)
{
try
{
checkIfNumericalValue();
testIfTextBoxOnesMinimumIsMet();
testIfTextBoxTwosMinimumIsMet();
displayResultToUser();
resetOrClose();
}
catch (ArgumentException ex)
{
// The error message we defined at the exception we threw
MessageBox.Show(ex.Message);
}
}
// Textbox One
public void testIfTextBoxOnesMinimumIsMet()
{
if (length < 3)
{
throw new ArgumentException("Length must be greater than 3 meters.");
}
}
An alternative would be to deal with the validation within your button like so:
// Button
private void myButton_Click(object sender, EventArgs e)
{
checkIfNumericalValue();
if (length < 3)
{
MessageBox.Show("Length must be greater than 3 meters.");
return;
}
testIfTextBoxTwosMinimumIsMet();
displayResultToUser();
resetOrClose();
}
What happens above is that the return will leave that function without further processing anything else.
So, if I'm understanding this correctly, if the text boxes contain numerical values, text box 1 meets the minimum and text box 2 meets the minimum, you want to displayResultToUser() and then resetOrClose().
If that's the case, you can have the 3 methods checkIfNumericalValue(), testIfTextBoxOnesMinimumIsMet() and testIfTextBoxTwosMinimumIsMet() return a bool depending on what the minimum condition is and then write something like this:
private void myButton_Click(object sender, EventArgs e)
{
if (checkIfNumericalValue() && testIfTextBoxOnesMinimumIsMet(Convert.ToInt32(txtBoxOne.Text)) && testIfTextBoxTwosMinimumIsMet(Convert.ToInt32(txtBoxTwo.Text)))
{
displayResultToUser();
resetOrClose();
}
}
public bool testIfTextBoxOnesMinimumIsMet(int length)
{
if (length < 3)
{
MessageBox.Show("length must be greater than 3 metres");
return false;
}
return true;
}
It appears that you need some other variable to track whether or not you have encountered errors. To do this, you could have a bool noErrors variable defined, and you should return a boolean from your error check methods that is True if there were no errors, otherwise False. This way you know if you ran into any problems.
Finally, you should check for the state of errrorsFound before running any of your other methods.
For example:
// Button
private void myButton_Click(object sender, EventArgs e)
{
bool noErrors =
isNumericalValue() &&
textBoxOnesMinimumIsMet() &&
textBoxTwosMinimumIsMet();
if (noErrors)
{
displayResultToUser();
resetOrClose(); // I'm not sure if this should happen regardless of errors?
}
}
// Textbox One
public bool textBoxOnesMinimumIsMet()
{
if (length < 3)
{
MessageBox.Show("length must be greater than 3 metres");
return false;
}
return true;
}
I have a label and I want it to display either Player or Console depending on what the variable answer is.
private void playerLabel_Click(object sender, EventArgs e)
{
string playerDetail = "Player",
consoleDetail = "Console";
if (Class.Method.Variable == 1)
{
Show.playerDetail();
}
if else (Class.Method.Variable == 0)
{
Show.consoleDetail();
}
}`
I then want to make it so that the label shows the string instead if you get me. I know I am not doing this properly but I can't work out how exactly to do this.
private void playerLabel_Click(object sender, EventArgs e)
{
string labelText = playerLabel.Text;
if (Class.Method.Variable == 1)
{
labelText = "Player";
Show.playerDetail();
}
else if(Class.Method.Variable == 0)
{
labelText = "Console";
Show.consoleDetail();
}
playerLabel.Text = labelText;
}
It would be better if your methods in Show class returned the appropriate string, so that you can do: playerLabel.Text = Show.WhateverDetail();. Additionally its even better if you could tie the Show method with the Variable value so that you don't have to use an if-else logic at all.
a. The Text property of the Label is what you want to set your strings to.
playerLabel.Text = playerDetail;
playerLabel.Text = consoleDetail;
b. Your if/else method should be in the form of:
if (test)
{
}
else if
{
}
else
{
}
You don't need the else if bit in the middle if there are only two branches.
c. I'm not sure about Show.consoleDetail() and Show.playerDetail(). Are 'consoleDetail()' and 'playerDetail()' method calls?
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;
}