Exception when clearing the all controls in a form - c#

I have some textboxes in my form. I wrote the code on leave event to add 0.00 automatically. I wrote the code to add two textboxes value to the third one as
try
{
decimal netVal = 0;
decimal.TryParse(txtNetValue.Text, out netVal);
decimal disc2 = 0;
decimal.TryParse(txtDisc2.Text, out disc2);
decimal tax1 = 0;
decimal.TryParse(txtTax1.Text, out tax1);
decimal tax = netVal - disc2;
string strtax = ((tax / 100) * tax1).ToString();
txtTax2.Text = strtax.Substring(0, strtax.IndexOf(".") + 3);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
In this case when I click the new button to clear all the controls I am getting an exception as Index and length must refer to a location within the string. Parameter name: length.

Your issue is here:
strtax.Substring(0, strtax.IndexOf(".") + 3);
I don't believe that Substring does what you think it does. The arguments are not "startIndex" and "endIndex" (Beginning and End), they are "startIndex" and "Length" (Beginning and length of substring). Most likely, this confusion is causing you to attempt to get a substring that is larger than the size of the string.
For example, you're saying I want the last 10 characters of "Test". "Test" only has four characters, so trying to get the "last ten" will cause that error.

It looks like your end goal is to have the value formatted as money. If this is the case then you can use the handy Decimal.ToString("C"). There are many other formats that you may want instead, see this link for more info on formatting.

Related

C# string.split on readline not producing expected array length

Hi guys just carrying on working on my first app, done mainly to learn and nothing else. I want the user to be able to type in 2d6+4 OR 2d6, you should be able to substitute those numbers for any number. I'm getting errors parsing the information and I think it has something to do with the array containing more or less values than I anticipated, or it for some reason left the delimiter in. typing 2d6+4 or 2d6 +4 works fine, 2d6 however does not, which is what I thought the if statement should guard against. Any ideas?
Console.WriteLine("Please type the roll you would like to perform, for example - 2d6+4");
var rollLine = Console.ReadLine();
var diceLine = rollLine.Split(new Char[] { 'd', '+' }, StringSplitOptions.RemoveEmptyEntries);
diceCount = int.Parse(diceLine[0]);
diceType = int.Parse(diceLine[1]);
if (rollLine.Length > 2)
{
bonus = int.Parse(diceLine[2]);
}
else
{
bonus = 0;
}
It looks like you are just using the wrong variable for the length comparison. You are comparing the length of the string, not the length of the split array. It should be:
if (diceLine.Length > 2)
When user entered "2d6", the string length is 3, i.e. following rule is true
if (rollLine.Length > 2)
However, as per your logic you will get array of 2 items in the diceLine, i.e. diceLine[0] and diceLine[1] but after condition with length you call diceLine[2] that does not exist.
I.e. either change condition to
if (rollLine.Length == 5) // 2d6+4
or check for the length of the array
if (diceLine.Length > 2)
You want your IF to check if the rollLine length is greater than 3, not 2.
As the smallest thing you'll type in is, for example, 2d6, you want to check for the bonus only when the rollLine is more than 3 characters.
if (rollLine.Length > 3)
{
bonus = int.Parse(diceLine[2]);
}

using a textbox to input the data in the scores textbox

Here is the right example
Need to use int data types.
SO, I am able to enter a number and but I get duplicate of a just one number.
Here is what I get on my code:
//create a string for the name
string name = txtName.Text;
// create a int for the number
// have those now have to get three amounts
// for each name then store that
// make a size three array
//innt to put the array in the for loop
int[] x = new int[3];
for (int i = 0; i < x.Length; i++)
{
//txtScore.Text
//txtStoreScores.Text
int covert = Int32.Parse(txtScore.Text);
x[i] = covert;
txtStoreScores.AppendText(x[i].ToString());
// ok I just need one number
// and split them by each number
}
Honestly, though you have selected an answer this feedback may be beneficial to future solutions. Your button once triggered should fire an event, inside that could you want to ensure you properly sanitize user input. Assume the user will cause an error, because the amount of variables they can input are infinite.
protected void btnAddScore_Click(object sender, EventArgs e)
{
if(float.TryParse(txtGrade.Text, out grade) && grade >= 0)
txtScores.Text += $"{grade}, ";
}
That simple conditional will sanitize, by ensuring that the user has entered a valid numeric and the score is higher than zero. Especially since a negative number would be unlikely. The primary point, your code should reflect the usage. Your code should account for those anomalies and variances that may occur.
Another nifty notion, you are outputting directly based on input. When you save that information, you would need to parse the data. So realize that you may need to something along these lines:
var scores = txtScores.Text.Split(','); // An array.
txtScores.Text = String.Join(",", scores); // Converts array into single string
The problem will increase in complexity over time, so be aware of that. Hopefully this was helpful. As for your math, if you do the following it would calculate:
var sum = txtScores.Text.Split(", ").Sum(grade => (float)grade);
The above makes a potentially flawed assumption, that all would cast to a float without an issue. These are items you need to think about. If you do not cast then your sum would be reflected by the length of your string not the values.
if i understand this right!!! you want to append the number from txtScore to txtStoreScores each time you click Add Scores btn!!!!
in this case you don't need a loop, simply put this in Add Scores btn event handler
txtStoreScores.Text += txtScore.Text + " ";
you reaaaaaly need to give more details and a clear question. Good luck!

Comparing a text box's input to a variable

My program requires users to input answers into a text box to randomly generated questions. The questions have calculated answers which are stored in variables. Comparing the text box's input with that variable doesn't work properly, hence why I'm here.
enum elements { lithium, beryllium, sodium, magnesium };
public void Moles()
{
string elementName;
int elementsLength = Enum.GetNames(typeof(elements)).Length;
double moles, mass, roundedMoles, Mr = 0;
Random random = new Random();
elementName = (Enum.GetNames(typeof(elements))[random.Next(0, elementsLength)]);
mass = random.Next(1, 100);
switch (elementName)
{
case "lithium":
Mr = 7;
break;
case "beryllium":
Mr = 9;
break;
case "sodium":
Mr = 23;
break;
case "magnesium":
Mr = 24;
break;
}
moles = mass / Mr;
roundedMoles = Math.Round(moles);
label1.Text = ("How many moles in " + mass + "g" + " of " + elementName + "?");
string input = textBox1.Text.ToString();
if (input == roundedMoles.ToString())
{
MessageBox.Show("Good");
textBox1.Clear();
}
else
{
MessageBox.Show("Bad");
textBox1.Clear();
}
private void button1_Click(object sender, EventArgs e)
{
Moles();
}
As you can see, the program will calculate a number of moles and round it to the nearest whole number. It's then stored in a variable, 'roundedMoles' - this variable is what's compared with the text box's input.
However, the message box will randomly show 'Good' or 'Bad' regardless of whether the input is correct or not. Bear in mind that this code works fine in a console application, so I don't know whether it's something I'm doing wrong or if it just doesn't want to work.
Sorry if this code isn't of a high standard. I'm not that good at programming.
You have two problems.
Don't compare strings as numbers
When comparing numeric values, never compare string to string. Always convert to a numeric variable. Otherwise, "0.00" will not equal "0" and "1234 " (with a space at the end) won't equal "1234" (with no space). Also, you will run into serious trouble if you're working with a culture that uses , as the decimal point.
So, instead of this:
string input = textBox1.Text.ToString();
if (input == roundedMoles.ToString())
{
MessageBox.Show("Good");
textBox1.Clear();
Use something like this:
string input = textBox1.Text;
double inputAsDouble;
bool ok = double.tryParse(out inputAsDouble);
if (!ok)
{
MessageBox.Show("Please enter a numeric value.");
return;
}
if (inputAsDouble == roundedMoles)
{
MessageBox.Show("Good");
textBox1.Clear();
Don't compare floating point values as exact
When comparing floating point values, don't use ==. Instead, compute the difference and make sure it is below a certain tolerance. You have to do this because floating point variables are only approximations.
So instead of
if (inputAsDouble == roundedMoles)
use
const double Tolerance = 0.00001;
if (inputAsDouble - roundedMoles < Tolerance)
Ok so here is the answer...
The reason the console works is that you write to the console to ask the question. You then do console.Readline() this captures the input of the answer after they have seen the question.
On the forms version. You set the label to the question and immediately capture the text box value. The user has not had a chance to enter the answer, or its still the answer from the last time (hence why it randomly goes from "Good" to "Bad" because sometimes the answer is the same).
One simple way is make your variables at the top of the Moles() method, class variables on the form and then have 2 buttons with 2 methods one that gets the questions and sets your answer variables and then a second button then the user can press when they've entered their answer.
Check out this code paste https://www.pastebucket.com/564406
(You'll need button2 added to your form for this to work obviously)
edit: I've done a quick cut and paste of code there. You shouldn't just copy this and use it. Look what I've done and apply it properly and try and understand why it works
It seems that you might have a culture related problem down there. Always be careful when comparing Double values converted to String. The framework might be converting '1,5' to '1.5' depending on your regional settings.
The first thing I would recomend you is not to compare as String but do it as Double. And if you do that, ensure that you will replace dots with comma or other way.
if (Convert.ToDouble(input) == roundedMoles)
{
MessageBox.Show("Good");
textBox1.Clear();
}
else
{
MessageBox.Show("Bad");
textBox1.Clear();
}

Getting a character from a string is returning an unexpected number?

I have a list box that contains the ID number and model of a number of cars, taken from an access table. I have some text boxes that will be filled with the data from that table when a car is selected from the list box. To get the id number of the selected car, I'm using this code:
int idNum = listBox1.SelectedItem.ToString()[0];
Which should get the first character in the item string (it's ID number). When I select the first item in the list, what I am instead getting is 49. My first thought was that I wasn't casting it to an int, so maybe the 49 represents some character code for the number, however
Convert.ToInt16(listBox1.SelectedItem.ToString()[0])
Returns the exact same number. The second item is 50, and so on and so forth.
I want to be changing how I get the ID number from this char conversion anyway, as it's just occurred to me that once I hit 10 cars it won't work, but why am I getting such a large, consistently offset, and (perhaps most bafflingly of all) multi-digit number from a c# equivalent of java's charAt[0]?
The specific error I've been getting is that there is no row at position 49, which pops up when I try to get the value of mydataset.Tables["mytable"].Rows[idNum]["CarID"].ToString();. Now, I can see a few things that could be causing this issue, I have absolutely know idea if Rows[idNum]["CarID"] is the correct syntax, and was very surprised to see that my guess worked, but it's still a very weird problem.
You need to get the numeric value for Char:
int idNum = (int)Char.GetNumericValue(listBox1.SelectedItem.ToString()[0]);
While int idNum = listBox1.SelectedItem.ToString()[0]); return the ASCII of Character '1' (example) which is 49.
This is the actual code from Microsoft for Convert.ToInt16:
public static short ToInt16(char value)
{
// Some validations
return (short)value;
}
Convert.ToInt16 for a char does an Explicit conversion, which gets the ASCII for that Character Value.
For Handling Multiple Digits:
string str = "37abcdef";
string myStrNumber = Regex.Match(str, #"\d+").Value;
int idNum2;
if (myStrNumber.Length > 0)
idNum2 = Convert.ToInt32(myStrNumber);
else
{
// Handle Error
}
Or Without using Regex :
string str = "37abcdef";
string myStrNumber = "";
for(int i = 0; i < str.Length; i++)
{
if (Char.IsNumber(str[i]))
myStrNumber += str[i];
}
int idNum2;
if (myStrNumber.Length > 0)
idNum2 = Convert.ToInt32(myStrNumber);
else
{
// Handle Error
}
Try this
int idNum = Convert.ToInt16(listBox1.SelectedItem.ToString()[0].ToString())
because
listBox1.SelectedItem.ToString()[0] return Char. If you convert a Char type data to Integer it will return ASCII of Char.
So Convert it into string before converting to Integer ( listBox1.SelectedItem.ToString()[0].ToString() ).
user3185569 identified the problem, but I'll put up the solution I ended up using for future reference. The int idNum = listBox1.SelectedItem.ToString()[0]); line was getting the ASCII for the character, 49 for 1, 50 for 2, etc. This can be solved by using (int)Char.GetNumericValue(listBox1.SelectedItem.ToString()[0]) -1;.
(int)Char.GetNumericValue gets the actual number value of that character, rather than the ASCII value. The - 1 is to account for the car ID's starting from 1, but the table indexes start from 0.
This still leaves the issue of digits, if the first character of the string is being used to get the ID number, as soon as there are more than 9 cars, the code won't work. The strings are written in the listbox as "[idNum]: [carName]". For example: 1: Astra. To get the ID number I used Split(':')[0], which splits the string into an array of substrings, splitting at each : character.
The working line of code is:
int idNum = Convert.ToInt16(listBox1.SelectedItem.ToString().Split(':')[0]) - 1;

C# getting first digit of int in custom class

I am trying to build a help function in my guess the number game, whereby the user gets the first digit of the number he/she has to guess. So if the generated number is 550, he will get the 5.
I have tried a lot of things, maybe one of you has an idea what is wrong?
public partial class Class3
{
public Class3()
{
double test = Convert.ToDouble(globalVariableNumber.number);
while (test > 10)
{
double firstDigit = test / 10;
test = Math.Round(test);
globalVariableNumber.helpMe = Convert.ToString(firstDigit);
}
}
}
Under the helpButton clicked I have:
private void helpButton_Click(object sender, EventArgs e)
{
label3.Text = globalVariableNumber.helpMe;
label3.AutoSize = true;
That is my latest try, I putted all of this in a custom class. In the main I putted the code to show what is in the helpMe string.
If you need more code please tell me
Why not ToString the number and use Substring to get the first character?
var number = 550;
var result = number.ToString().Substring(0, 1);
If for some reason you dont want to use string manipulation you could do this mathematically like this
var number = 550;
var result = Math.Floor(number / Math.Pow(10, Math.Floor(Math.Log10(number))));
What's wrong - you have an infinite while loop there. Math.Round(test) will leave the value of test unchanged after the first iteration.
You may have intended to use firstDigit as the variable controlling the loop.
Anyway, as suggested by others, you can set helpMe to the first digit by converting to a string and using the first character.
As an aside, you should consider supplying the number as a parameter and returning the helpMe string from the method. Your current approach is a little brittle.
The problem with your code is that you are doing the division and storing that in a separate variable, then you round the original value. That means that the original value only changes in the first iteration of the loop (and is only rounded, not divided), and unless that happens to make the loop condition false (i.e. for values between 10 and 10.5), the loop will never end.
Changes:
Use an int intead of a double, that gets you away from a whole bunch of potential precision problems.
Use the >= operator rather than >. If you get the value 10 then you want the loop to go on for another iteration to get a single digit.
You would use Math.Floor instead of Math.Round as you don't want the first digit to be rounded up, i.e. getting the first digit for 460 as 5. However, if you are using an integer then the division truncates the result, so there is no need to do any rounding at all.
Divide the value and store it back into the same variable.
Use the value after the loop, there is no point in updating it while you still have multiple digits in the variable.
Code:
int test = (int)globalVariableNumber.number;
while (test >= 10) {
test = test / 10;
}
globalVariableNumber.helpMe = test.ToString();
By using Math.Round(), in your example, you're rounding 5.5 to 6 (it's the even integer per the documentation). Use Math.Floor instead, this will drop the decimal point but give you the number you're expecting for this test.
i.e.
double test = Convert.ToDouble(globalVariableNumber.number);
while (test > 10)
{
test = Math.Floor(test / 10);
globalVariableNumber.helpMe = Convert.ToString(firstDigit);
}
Like #Sam Greenhalgh mentions, though, returning the first character of the number as a string will be cleaner, quicker and easier.
globalVariableNumber.helpMe = test >= 10
? test.ToString().SubString(0, 1)
: "Hint not possible, number is less than ten"
This assumes that helpMe is a string.
Per our discussion in the comments, you'd be better off doing it like this:
private void helpButton_Click(object sender, EventArgs e)
{
label3.Text = GetHelpText();
label3.AutoSize = true;
}
// Always good practice to name a method that returns something Get...
// Also good practice to give it a descriptive name.
private string GetHelpText()
{
return test >= 10 // The ?: operator just means if the first part is true...
? test.ToString().SubString(0, 1) // use this, otherwise...
: "Hint not possible, number is less than ten" // use this.
}

Categories

Resources