Stackoverflow exception from updating combobox in winforms/C# - c#

I'm geting a StackOverflowException. Somehow, posting here seemed appropriate.
I'm using Windows Forms in a C# application. This application is intended to run on Linux, FreeBSD and Mac-OS, so I can't use WPF, so please don't suggest it.
My guess is that I'm missing a nuance of WinForms, but I cant seem to figure out what.
The ComboBox is generated by the GUI form builder in VS 2010.
The specific lines of code that are throwing the error are here:
if(cur_num_is_valid)
{
cbx_material_num.Text = num;
}
else
{
num = "0";
//I only have one of the following two at a time. Both overflow
cbx_material_num.SelectedIndex = 0;
cbx_material_num.Text = "0";
}
Since the code is somewhat complex, here's the whole function code. 'cbx_' indicates a combo box. 'txtb_' is a text box.
private void cbx_material_numobj_SelectedIndexChanged(object sender, EventArgs e)
{
string obj = cbx_material_obj.Text;
string num = cbx_material_num.Text;
int selnum = 0;
int n = 0;
//do we need to recreate the numbers array?
bool cur_num_is_valid = false;
cbx_material_num.Items.Clear();
if(obj != lastobj)
{
n = m_demo.get_object_modifiers(obj);
for(int i = 0; i <= n; i++)
{
string s = i.ToString();
if(s == num && i < n) cur_num_is_valid = true;
cbx_material_num.Items.Add(s);
}
}
if(cur_num_is_valid)
{
cbx_material_num.Text = num;
}
else
{
num = "0";
//Overflow here:
cbx_material_num.SelectedIndex = 0;
}
try
{
selnum = int.Parse(num);
}
catch(Exception)
{
MessageBox.Show("Error, second select menu after 'object modifiers' must be a number, not '"+num+"'.");
cbx_material_num.Text="0";
return;
}
if(selnum >= n)
{
txtb_material_param1.Text = "0";
txtb_material_param2.Text = "0";
txtb_material_param3.Text = "0";
txtb_material_param4.Text = "0";
}
else
{
MaterialFace face;
MaterialParameter parameter;
int typeid;
object paramdata;
m_demo.get_object_modifiers_material(obj, selnum, out face, out parameter, out typeid, out paramdata);
cbx_material_face.Text = face.ToString();
cbx_material_paramtype.Text = parameter.ToString();
switch(typeid)
{
case 0:
txtb_material_param1.Text = ((float)paramdata).ToString();
cbx_material_datatype.Text = "float";
goto case -1;
case 1:
float[] parsf = ((float[])paramdata);
txtb_material_param1.Text = parsf[0].ToString();
txtb_material_param2.Text = parsf[1].ToString();
txtb_material_param3.Text = parsf[2].ToString();
txtb_material_param4.Text = parsf[3].ToString();
cbx_material_datatype.Text = "float[]";
break;
case 2:
txtb_material_param1.Text = ((int)paramdata).ToString();
cbx_material_datatype.Text = "int";
goto case -1;
case 3:
int[] parsi = ((int[])paramdata);
txtb_material_param1.Text = parsi[0].ToString();
txtb_material_param2.Text = parsi[1].ToString();
txtb_material_param3.Text = parsi[2].ToString();
txtb_material_param4.Text = parsi[3].ToString();
cbx_material_datatype.Text = "int[]";
break;
case -1: //can't actuall be returned, used to 'blank' the last three as '0'
txtb_material_param2.Text = "0";
txtb_material_param2.Text = "0";
txtb_material_param3.Text = "0";
break;
case 4:
OpenTK.Graphics.Color4 paramc = ((OpenTK.Graphics.Color4)paramdata);
txtb_material_param1.Text = paramc.R.ToString();
txtb_material_param2.Text = paramc.G.ToString();
txtb_material_param3.Text = paramc.B.ToString();
txtb_material_param4.Text = paramc.A.ToString();
cbx_material_datatype.Text = "Color4";
break;
default: //5
Vector4 paramv = ((Vector4)paramdata);
txtb_material_param1.Text = paramv.X.ToString();
txtb_material_param2.Text = paramv.Y.ToString();
txtb_material_param3.Text = paramv.Z.ToString();
txtb_material_param4.Text = paramv.W.ToString();
cbx_material_datatype.Text = "Vector4";
break;
}
}
}

You need to check that the SelectedIndex isn't already 0 before you try to set it:
if (cbx_material_num.SelectedIndex != 0){
cbx_material_num.SelectedIndex = 0;
}
Otherwise you're re-firing the event every time through.

I think that whenever you set this cbx_material_num.SelectedIndex = 0; within the EventHandler you invoke your
cbx_material_numobj_SelectedIndexChanged(object sender, EventArgs e)
Each call invokes another eventHandler so the stack fills up after some time.
Basically, the fact that it is called SelectedIndexChanged doesn't mean that the value has to be different from the previous one but that the value is set through its setter.

Related

NullReferenceException in array of objects [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 1 year ago.
I'm working on a program in c# in which I've got an array of objects of a class. I've got a constructor in the class that should give the attached string a value of "" to make sure they're empty so information can be passed in easily. I then have the array created like so:
participants[8][8] grid = new participants[8][];
But I'm being thrown a NullReferenceExcetption error. Here is my code for your reference.
using System;
namespace TreasurehuntCsharp
{
class square
{
public string strX = "";
public int y = 0;
public int x = 0;
}
class participants
{
public string name = "";
public string contact = "";
public participants()
{
name = "";
contact = "";
}
}
class Program
{
//Method for user to choose a square
static void Input(square Coord)
{
//Variables
bool correct = false;
//Inputs
Console.WriteLine("Please enter the coordinates of the square you would like to select: \r\n");
do
{
//X coordinate
Console.WriteLine("X: ");
Coord.strX = Console.ReadLine().ToLower();
//Convert letter to array coordinate
switch (Coord.strX)
{
case "a":
Coord.x = 0;
correct = true;
break;
case "b":
Coord.x = 1;
correct = true;
break;
case "c":
Coord.x = 2;
correct = true;
break;
case "d":
Coord.x = 3;
correct = true;
break;
case "e":
Coord.x = 4;
correct = true;
break;
case "f":
Coord.x = 5;
correct = true;
break;
case "g":
Coord.x = 6;
correct = true;
break;
case "h":
Coord.x = 7;
correct = true;
break;
default:
Console.WriteLine("Please enter a letter from A to H");
correct = false;
break;
}
} while (correct != true);
correct = false;
do
{
//Y coordinate
Console.WriteLine("Y: ");
Coord.y = Convert.ToInt32(Console.ReadLine());
if (Coord.y >= 1 && Coord.y <= 7)
{
correct = true;
}
else
{
Console.WriteLine("Please input an integer value from 1 to 7.");
correct = false;
}
} while (correct != true);
}
static void ParticipantDetails(participants User)
{
Console.WriteLine("Please input your name and Contact number: ");
//User name input
Console.WriteLine("Name: ");
User.name = Console.ReadLine();
//User contact number input
Console.WriteLine("Number: ");
User.contact = Console.ReadLine();
}
static void Main(string[] args)
{
//Objects
square Coord = new square();
participants User = new participants();
//Initialise 2D array
participants[][] grid = new participants[8][];
//Variables
bool correct = false;
do
{
//Methods
Input(Coord);
ParticipantDetails(User);
//Input data to array
if (grid[Coord.x][Coord.y].name == "" && grid[Coord.x][Coord.y].contact == "")
{
grid[Coord.x][Coord.y].name = User.name;
grid[Coord.x][Coord.y].contact = User.contact;
Console.WriteLine(grid[Coord.x][Coord.y]);
correct = true;
}
else
{
Console.WriteLine("That square is already filled. Please try again.");
correct = false;
}
} while (correct == false);
}
}
You did not initialize all the dimensions of the array.
//Initialise 2D jagged array
participants[][] grid = new participants[8][];
// You can do that in a for loop
grid[0] = new participants[8];
grid[1] = new participants[8];
grid[2] = new participants[8];
...
grid[7] = new participants[8];
// For loop equivalent
for (int i = 0; i < grid.Length; i++)
{
grid[i] = new participant[8];
}
A better way for your case (since all the sub-arrays have the same number of elements), would be to use multidimensional-arrays
participants[,] grid = new participants[8,8];
// and access like this
grid[Coord.x, Coord.y]
You created an array of arrays.
participants[][] grid = new participants[8][];
It is an array with 8 entries. Each of the entries is supposed to be an array of participants, but it hasn't been created.
What you need to do is to create 8 arrays and assign them to the elements of the grid array.
participant[][] grid = new participant[8][];
for (int i = 0; i < grid.Length; i++)
grid[i] = new participant[8];
Here I assume that each element of the grid array is also going to contain 8 elements, but it's up to you.

C# Use of unassigned local variables (int)

I am wondering what I am doing wrong, as I am trying to make a menu, in which it needs to calculate three different courses together in predefined values, however I seem to be doing the conversions wrong, as I cant seem to make it work right.
int a, b, c;
textBox4.Text = (a + b + c).ToString();
if (comboBox1.Text == "Tzatziki")
{
a = 35;
}
else if (comboBox1.Text == "Carpaccio")
{
a = 40;
}
else if (comboBox1.Text == "Bruscetta")
{
a = 30;
}
else if (comboBox1.Text == "Shrimp Cocktail")
{
a = 40;
}
if (comboBox2.Text == "Sirloin")
{
b = 225;
}
else if (comboBox2.Text == "Lamb")
{
b = 195;
}
else if (comboBox2.Text == "Salmon")
{
b = 170;
}
else if (comboBox2.Text == "Veggy")
{
b = 100;
}
if (comboBox1.Text == "Chocolate Cake")
{
c = 45;
}
else if (comboBox1.Text == "Pancakes")
{
c = 35;
}
else if (comboBox1.Text == "Waffles")
{
c = 40;
}
else if (comboBox1.Text == "Sundae")
{
c = 38;
}
}
Would appreciate the advice, kinda new to C# programming :)
Give value to your variables and initialize them:
int a = 0, b = 0, c = 0;
And I think you need to move this line end of your if / else-if statements:
textBox4.Text = (a + b + c).ToString();
Before you can convert an integer, to its textual counterpart, you need to give it an initial value.
The reason why you get zero is because after you initialize variables (with zero), you immediately use them. In that sence the if-then-else patterns are useless.
A possible fix is to use switch-case patterns to ease coding and after you calculated a, b and c, set the text value:
int a = 0, b = 0, c = 0;
switch(comboBox1.Text) {
case "Tzatziki" :
a = 35;
break;
case "Carpaccio" :
a = 40;
break;
case "Bruscetta" :
a = 30;
break;
case "Shrimp Cocktail" :
a = 40;
break;
}
switch(comboBox2.Text) {
case "Sirloin" :
b = 225;
break;
case "Lamb" :
b = 195;
break;
case "Salmon" :
b = 170;
break;
case "Veggy" :
b = 100;
break;
}
switch(comboBox3.Text) {
case "Chocolate Cake" :
c = 45;
break;
case "Pancakes" :
c = 35;
break;
case "Waffles" :
c = 40;
break;
case "Sundae" :
c = 38;
break;
}
textBox4.Text = (a + b + c).ToString();
You probably made even a mistake for c, since you used ComboBox1 again (I expect this should be ComboBox3. By using a switch-case structure, the code becomes more elegant.
A final problem with the code is what to do if no value has been entered in the combobox (or a different one from what you have checked). In the case I wrote above, the values will remain 0 (only the values corresponding to the ComboBox that has an unknown value). You can add a defaut : case in order to decide what to do then.

How to assign data to an int if I checked radio button

I want to assign a data to an int volunteerEducation if I Checked radio button to save it to the database!
int volunteerEducation;
switch (volunteerEducation)
case radioButton9.Checked:
volunteerEducation= 9;
break;
case radioButton10.Checked:
volunteerEducation = 10;
break;
try this...
foreach(Control c in this.Controls)
{
if(c is RadioButton)
{
RadioButton rbtn = (RadioButton)c;
// now here you can use if else statements or Switch Statement
}
}
switch allows you to check for one of several values on a single variable. if statements allow arbitrary conditions, which can check a single variable or many. Hence, switch is unsuited for what you are trying to do.
There are a few obvious options:
Use a series of if ... else if statements
Use some fancier construct such as a lookup dictionary mapping to methods (Dictionary<RadioButton,Func<>> might be a good place to start), though if you are unfamiliar with such constructs as switch I'd strongly recommend against that (it's the old "you have to learn to walk before you start to run")
Iterate over the radio buttons and do your magic inside a loop
Such a loop would look like:
foreach (Control c in this.Controls)
{
RadioButton rbtn = c as RadioButton;
if(rbtn != null)
{
// ... your code to work with 'rbtn' goes here ...
if (rbtn.Checked)
{
// ...
}
}
}
Using as rather than is followed by an explicit cast is idiomatic, and also saves you a cast; null checking is almost certainly faster, and certainly not slower, than casting. The as operator gives you null if the given value cannot be cast to the given type. In the case where the value of the variable you are working can be changed from another thread (not likely in this case, but possible in other cases), it also saves you the headache of a nigh-impossible-to-reproduce bug when something changes the value of the variable out under your feet.
A set of if statements to do the same thing would be along the lines of
if (radioButton9.Checked)
{
// do something
}
else if (radioButton10.Checked)
{
// do something
}
Using else if mimics the behavior of a switch ... case ... break construct. If they are independent, simply omit the else. (Then, I'd suggest adding a blank line between the end of the if statement-block and the next if statement, for readability.)
I found the Answer and it's not really different from thus answers.
the Point is to declare int. e.g int volunteerEducation = 0; then you have to use if ... else if.
private void updateButton_Click(object sender, EventArgs e)
{
try
{
string volunteerID = updtIDTextBox.Text;
string volunteerName = updtNameTextBox.Text;
string volunteerZone = updtZoneTextBox.Text;
string volunteerStreet = updtStreetTextBox.Text;
int volunteerSex = updtMaleRadioButton.Checked ? 0 : 1;
DateTime volunteerBirthday = updtBirthdayDateTimePicker.Value;
if (updtHomePhoneTextBox.Text == "")
updtHomePhoneTextBox.Text = "0";
int volunteerHomePhone = int.Parse(updtHomePhoneTextBox.Text);
if (updtWorkPhoneTextBox.Text == "")
updtWorkPhoneTextBox.Text = "0";
int volunteerWorkPhone = int.Parse(updtWorkPhoneTextBox.Text);
if (updtMobile1TextBox.Text == "")
updtMobile1TextBox.Text = "0";
int volunteerMobile1 = int.Parse(updtMobile1TextBox.Text);
if (updtMobile2TextBox.Text == "")
updtMobile2TextBox.Text = "0";
int volunteerMobile2 = int.Parse(updtMobile2TextBox.Text);
string volunteerEmail = updtEmailTextBox.Text;
string volunteerJob = updtJobTextBox.Text;
string volunteerAffiliation = updtAffiliationTextBox.Text;
//The solution start from here
int volunteerEducation = 0;
if (radioButton10.Checked)
volunteerEducation = 1;
else if (radioButton11.Checked)
volunteerEducation = 2;
else if (radioButton12.Checked)
volunteerEducation = 3;
else if (radioButton14.Checked)
volunteerEducation = 5;
else if (radioButton15.Checked)
volunteerEducation = 6;
else if (radioButton16.Checked)
volunteerEducation = 7;
else if (radioButton17.Checked)
volunteerEducation = 8;
else if (radioButton18.Checked)
volunteerEducation = 9;
//end solution
string volunteerEducationPlace = addEducationPlaceTextBox.Text;
string volunteerEducationDepartmen = addEducationDepartmentTextBox.Text;
//same above
int volunteerInteresting = 0;
if (updtIntrstMdcnRadioButton.Checked)
volunteerInteresting = 1;
else if (updtIntrstSosclRadioButton.Checked)
volunteerInteresting = 2;
else if (updtIntrstLrnRadioButton.Checked)
volunteerInteresting = 3;
else if (updtIntrstTrnRadioButton.Checked)
volunteerInteresting = 4;
//end
string volunteerNotes = addNotesTextBox.Text;
int x = dataGridViewX1.SelectedRows[0].Index;
UpdateVolunteer(volunteerID, volunteerName, volunteerZone, volunteerStreet, volunteerSex, volunteerBirthday, volunteerHomePhone, volunteerWorkPhone, volunteerMobile1, volunteerMobile2, volunteerEmail, volunteerJob, volunteerAffiliation, volunteerEducation, volunteerEducationPlace, volunteerEducationDepartmen, volunteerInteresting, volunteerNotes);
showVolunteers(x);
updtIDTextBox.Text = "";
updtNameTextBox.Text = "";
updtZoneTextBox.Text = "";
updtStreetTextBox.Text = "";
updtBirthdayDateTimePicker.Value = DateTime.Now;
updtHomePhoneTextBox.Text = "";
updtWorkPhoneTextBox.Text = "";
updtMobile1TextBox.Text = "";
updtMobile2TextBox.Text = "";
updtEmailTextBox.Text = "";
updtJobTextBox.Text = "";
updtAffiliationTextBox.Text = "";
updtEducationPlaceTextBox.Text = "";
updtEducationDepartmentTextBox.Text = "";
updtNotesTextBox.Text = "";
}
catch (SqlException sql)
{
MessageBoxEx.Show(sql.Message);
}
}

SubMenu in C# using WindowsForm?

I have a menustrip consists of Menu and Tools
in "Menu" i have subMenus like msO1,msO2,msO3......., and on "Tools" i have subMenus like msP1,msP2,msP3.......,
on Form load all the subMenus visible is false..., On button Click user want to select which subMenus he want...,
in the textBox(txtSelect) if user enter 1,3..., he get msO1, msO3.....,
my code is a hardcode..., if i have 20 subMenus means this code is not helpfull anybody have an idea...,
private void btnSelect_Click_1(object sender, EventArgs e)
{
msO1.Visible = false;//msO1 is a submenu
msO2.Visible = false;
msO3.Visible = false;
msP1.Visible = false;
msP2.Visible = false;
msP3.Visible = false;
string word = txtSelect.Text;
string[] splt = word.Split(',');
int[] arrayItms = new int[splt.Length];
for (int x = 0; x < splt.Length; x++)
{
arrayItms[x]=Convert.ToInt32(splt[x].ToString());
if (splt.Length > 0)
{
switch (arrayItms[x])
{
case 1:
msO1.Visible = true; break;
case 2:
msO2.Visible = true; break;
case 3:
msO3.Visible = true; break;
case 4:
msP1.Visible = true; break;
case 5:
msP2.Visible = true; break;
case 6:
msP3.Visible = true; break;
}
}
}
}
Create an array of your MenuStrip
MenuStrip[] mstrip = new MenuStrip[]
{
msO1,msO2, msO3, msP1, msP2, msP3 // add other menus here when needed
};
now you could work on the array as a Whole to make visible or not your menus
for(int x = 0; x < menus.Length; x++)
mstrip[x].Visible = false;
and your code could be simplified with
for (int x = 0; x < splt.Length; x++)
{
int menuIndex;
if(Int32.TryParse(splt[x], out menuIndex))
{
menuIndex--;
if(menuIndex >= 0 && menuIndex < mstrip.Length)
mstrip[menuIndex].Visible = true;
}
}
Remember, arrays indexes start at zero (while your user will probably start counting a 1).
You could use something like this
string word = txtSelect.Text;
string[] splt = word.Split(',');
for (int x = 0; x < splt.Length; x++)
{
Control myControl1 = FindControl("ms" + splt[x]);
if ( myControl1 != null )
(ToolStripMenuItem)myControl1.Visible = true;
}
Untested but this should get you half way there I hope.
Loop through each ToolStripMenuItem control in the menu strip items and set them to visible.
You can add further conditions inside the loop to define which of the menu items should be made visible based on the users choice..
foreach (ToolStripMenuItem mi in menuStrip1.Items)
{
mi.Visible = true;
}

NullReferenceException even when control is present in the previous page

Whenever I try to retrieve the previous page dropdownlist control in bedCount() mwethod it gives this exception while I rest assure you that the control which I am searching is very much present in the previous page. What is the reason for this? My code is given below :
public partial class Room2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
DropDownList[] adult=new DropDownList[6];
DropDownList[] child = new DropDownList[6];
TableRow[] trp = new TableRow[5];
TableRow[] trc ={ trc1, trc2, trc3, trc4, trc5 };
DropDownList[] rtype ={ DropDownList1,DropDownList2, DropDownList3, DropDownList4, DropDownList5, DropDownList6 };
Label[] bed ={Label1,Label2,Label3,Label4,Label5,Label6};
int i,x,c=2;
for (i = 0; i < 5; i++)
{
trp[i] = (TableRow)PreviousPage.Master.FindControl("ContentPlaceHolder1").FindControl("tr" + (i + 1));
}
for (i = 0; i < 6; i++,c+=4)
{
adult[i] = (DropDownList)PreviousPage.Master.FindControl("ContentPlaceHolder1").FindControl("DropDownList" + c++);
child[i] = (DropDownList)PreviousPage.Master.FindControl("ContentPlaceHolder1").FindControl("DropDownList" + c);
}
for (i = 0; i < 6; i++)
{
x = adult[i].SelectedIndex + child[i].SelectedIndex;
switch (x)
{
case 0:
case 1:
rtype[i].Items.Add("Executive Class");
rtype[i].Items.Add("Business Class");
rtype[i].Items.Add("Gold Class (Type-I)");
rtype[i].Items.Add("Gold Class (Type-II)");
rtype[i].SelectedIndex = 0;
bed[i].Text = "No";
break;
case 2:
rtype[i].Items.Add("Business Class");
rtype[i].Items.Add("Gold Class (Type-I)");
rtype[i].Items.Add("Gold Class (Type-II)");
rtype[i].SelectedIndex = 0;
bed[i].Text = "1";
break;
case 3:
bed[i].Text = "1";
goto case 4;
case 4:
rtype[i].Items.Add("Gold Class (Type-I)");
rtype[i].Items.Add("Gold Class (Type-II)");
rtype[i].SelectedIndex = 0;
bed[i].Text = "2";
break;
case 5:
bed[i].Text = "2";
goto case 6;
case 6:
rtype[i].Items.Add("Gold Class (Type-II)");
rtype[i].SelectedIndex = 0;
bed[i].Text = "3";
break;
}
if (i<5 && trp[i].Visible)
trc[i].Visible = true;
}
}
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
if(DropDownList1.Items.Count<=3)
bedCount(DropDownList1,Label1,0);
}
protected void bedCount(DropDownList d,Label l,int a)
{
protected void bedCount(DropDownList d,Label l,int x)
{
DropDownList a=new DropDownList();
DropDownList c = new DropDownList();
int s;
a = (DropDownList)PreviousPage.Master.FindControl("ContentPlaceHolder1").FindControl("DropDownList"+x++);//gives exception here
c = (DropDownList)PreviousPage.Master.FindControl("ContentPlaceHolder1").FindControl("DropDownList"+x);
s = c.SelectedIndex + c.SelectedIndex;
if (d.SelectedItem.Equals("Business Class"))
if(s==2)
l.Text = "1";
else
l.Text = "No";
else if(d.SelectedItem.Equals("Gold Class (Type-I)"))
if(s==3)
l.Text = "1";
else if(s==4)
l.Text = "2";
else
l.Text = "No";
else if(d.SelectedItem.Equals("Gold Class (Type-II)"))
if(s==4)
l.Text = "1";
else if(s==5)
l.Text = "2";
else if(s==6)
l.Text = "3";
else
l.Text = "No";
}
When you change selected item in DropDownList1, then each item of your arrays
DropDownList[] adult=new DropDownList[6];
DropDownList[] child = new DropDownList[6];
will become a null because the page is recreated after each postback (even after changing dropdown list selected item)
On the first load of page you get your arrays filled because you fill them manually in Page_Load

Categories

Resources