"IndexOutOfRangeException: Index was outside of the array." exception occured - c#

I encountered this exception while setting the SetKeyName method of ImageCollection of ImageList.
this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream")));
this.imageList1.TransparentColor = System.Drawing.Color.Fuchsia;
this.imageList1.Images.SetKeyName(0, "");
this.imageList1.Images.SetKeyName(1, "");
i have used this "imageList1.ImageStream" in my Main Form too, and it works fine there. I am stuck here and i do not know what actually this issue is, how it raised and how can i solve this.
Any suggestions and comments will be much appreciated. Thank you!!

Try this:
this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream")));
this.imageList1.TransparentColor = System.Drawing.Color.Fuchsia;
for (int i = 0; i < this.imageList1.Images.Count; i++)
this.imageList1.Images.SetKeyName(i, "");

Most likely this line :
this.imageList1.Images.SetKeyName(1, "");
Is causing your exception. Of course it could also be the first line with Index 0. Basically the exception is saying that code failed while trying to access the array at a given index. The reason being that the array doesn't have an item at that index.
For example in your case the code assumes that there are 2 items in the array. One at index 0 and one at index 1. If the array has only one item the second line will fail and throw the exception.
All you have to do is make sure you have an item at a given index before you try to perform any operations on it.
Something like :
if(this.imageList1.Images.Count >= 2)
{
this.imageList1.Images.SetKeyName(1, "");
}

Related

Out of bounds exception whilst using arrays

I have an array of textboxes in which they change dyanmically depending on what the user types in. Those textboxes contain a number which represents a score of an assignment. Those score are linked to a module object. So if the user has 3 modules; 2 assignments on the first and second module and 3 assignments on the third module; then in total there would be 7 textboxes created for the user to input all their assignment marks.
What I am trying to do is to create a keyup event handler in which it gets the number in typed in by the user, and then dynamically calls a method to display the average of the the module. This is what I have so far. The following method gets called whenever the user types in a character:
public void calculateLevel4Modules(int counter) {
//iterate through modules
//iterate through assignts in that module
//whilst iterating, check tb and set userscore
//after iterating, update overall label with regards to modulecounter
//int assignmentCounter = 0;
//Console.WriteLine("in If statement.. " + counter);
for (int moduleCounter = 0; moduleCounter < requiredLevelList().Count; moduleCounter++)
{
int totalNumberOfAssignmentsInCurrentModule = requiredLevelList().ElementAt(moduleCounter).Assignments.Count;
Console.WriteLine("total number of assignmetns: " + totalNumberOfAssignmentsInCurrentModule);
assignmentCounter = assignmentCounter + totalNumberOfAssignmentsInCurrentModule;
Console.WriteLine("assignment counter: " + totalNumberOfAssignmentsInCurrentModule);
if (counter < assignmentCounter)
{
Console.WriteLine("in If statement.. " + userMarksTBLvl4[moduleCounter].Text);
try
{
int userMark = int.Parse(userMarksTBLvl4[counter].Text);
requiredLevelList().ElementAt(moduleCounter).Assignments.ElementAt(counter).UsersScore = userMark;
double modAvg = requiredLevelList().ElementAt(moduleCounter).getModuleScoreOverall();
moduleOverallLvl4[moduleCounter].Text = modAvg.ToString();
break;
}
catch (FormatException) { break; }
}
else { }
}
it works fine if the user has one module but if the user has two or more, then I get an error in the following line:
requiredLevelList().ElementAt(moduleCounter).Assignments.ElementAt(counter).UsersScore = userMark;
I am getting an out of bounds exception. I know why; its because counter is basically the # of the textbox that was typed into but by me using counter, I am accessing something not within the assignments list. This is an example of when the problem occus:
The user has 2 modules. In each module there are 2 assignments thus 4 textboxes are been created with their index ranging from 0 - 3. If the user wants to type in their score of the first assignment on the second module, its basically trying to write to the third index in that element then it crashes since that module only consist of 2 assignments.
There are some strange things in your code that make it hard to answer. First, the code you posted doesn't compile, so we have no way to test it.
Several times you use code like:
requiredLevelList().ElementAt(moduleCounter)
I assume requiredLevelList is a method that returns a list of things. There is no reason to assume requiredLevelList returns the same list, or even lists with the same number of elements, each time you call it. Maybe it does in your particular case, but this is a dangerous thing to rely on. You should use a construct like:
foreach (var module in requiredLevelList())
{
int totalNumberOfAssignmentsInCurrentModule = module.Assignments.Count;
...
module.Assignments.ElementAt(counter).UsersScore = userMark;
...
}
Code like this:
Console.WriteLine("total number of assignmetns: " + totalNumberOfAssignmentsInCurrentModule);
is symptomatic of trying to debug something after it has crashed. That is extremely inefficient. Learn how to use a debugger; you will not become an effective programmer until you know how to do this.
requiredLevelList().ElementAt(moduleCounter).Assignments.ElementAt(counter).UsersScore = userMark;
You're probably getting an out-of-bounds exception here because counter is outside the indexes of Assignments. Since you never initialize or change counter, I have no way to know what it is or should be. A debugger will tell you this, use one.
the # of the textbox that was typed into but by me using counter, I am accessing something not within the assignments list.
OK, if you're typing something “not within the assignments list” then you have to test for that and decide what to do. Perhaps something like:
if (counter >= 0 && counter < module.Assignments.Count)
module.Assignments.ElementAt(counter).UsersScore = userMark;
else
throw new Exception("I really have no idea what you want to do here.");
This also looks wrong:
moduleOverallLvl4[moduleCounter].Text = modAvg.ToString();
You never tell us what moduleOverallLvl4 is, but here you're assuming it has the same size as what is returned by requiredLevelList(). Maybe they are in this particular case, but that is a dangerous assumption. If these values are related, moduleOverallLvl4 should be contained in whatever class implements requiredLevelList, and you should have a method that assigns getModuleScoreOverall() to the correct element of moduleOverallLvl4.

Undo Operation fails on Repeated Use

I created an undo operation to set the current Value to the previous one that was within a list. It accomplishes this by removing the most recent index from the list and setting the value to the value that is behind it. Currently it works when there no value with in the list at initialization, as well as if there is more than one value within the list.
The code the way it is works when there is at least one index in the array, as previous unit tests pass this.
The problem is occurring where I try to have the InvalidOperationException to pass when the command is run twice, after the last item in the list has also been removed. so Add(5) -> Undo() -> Undo() to give an example. Also changing the if statement from valDict.Count > 0 to Value > 0, the same error occurs.
List<int> valDict = new List<int>();
public void Undo()
{
repOp1 = "Undo";
Console.WriteLine("1: " + valDict.Count);
if ( valDict.Count > 0)
{
int temp = valDict.Count - 1;
Console.WriteLine("2: " + temp);
valDict.RemoveAt(temp);
Console.WriteLine("3: " + valDict.Count);
valDict.TrimExcess();
//Below Line is flagged as the error
Value = valDict[valDict.Count-1];
}
else
{
throw new InvalidOperationException();
}
}
Can someone looking at this with fresh eyes, point out a possible solution, but not a fixed implementation, as I need to fix the implementation myself.
You can control that your List is not empty before getting the Value: list.Count==0, or !list.Any().

RowNotInTableException being thrown for DataTable when it shouldn't?

I'm not sure why this exception is happening... I could understand if I wasn't checking for i < table.Rows.Count but I do check for this, so I am confused as to why the row is not in the table... I've hit a roadblock here and could use someone a little more experienced with this problem than me. I just hope it's one of those small stupid mistakes.
Edit: Earlier on I had a debug line myTable.Rows[0]["FieldName"] and myTable.Rows[1]["FieldName"]. The second one threw the exception as well, the first did not.
internal Collection<fieldDef> DefaultList
{
get
{
Collection<fieldDef> listFields = new Collection<fieldDef>();
listFields.Clear();
//Rows.Count is checked here, which is why I'm so confused...
for (int i = 0; i < myTable.Rows.Count; i++)
{
string strFieldName = "";
if (myTable.Rows[i]["FieldName"].ToString() != "") //Exception happens here
{
strFieldName = myTable.Rows[i]["FieldName"].ToString();
}
FieldType type = FieldType.Character;
if (myTable.Rows[i]["FieldType"].ToString() != "") type = (FieldType)Enum.Parse(typeof(FieldType), myTable.Rows[i]["FieldType"].ToString());
//
//Other Similar lines to that above
//
fieldDef def = new fieldDef(i, strFieldName, strFieldName, type, /*other items...*/);
listFields.Add(def);
}
return listFields;
}
set
{
//Nothing negative happens here, left out for simplicity
}
}
I found the solution. Just posting in case anyone has the same problem. It's not stated in the original post, but this is called via change/edit events on the DataTable (which are triggered by button clicks and required to save settings).
The issue is that if you try to get the property within the event, the row is actually pulled from the table (like when it is being moved up or down) and the state is "detached", therefore, no longer officially in the table.
To solve this, I simply waited to access my property until after the event had completely finished (thus the row being fully placed back into the table) which required a little reworking of other parts of my code.
Hope this helps someone down the road!
I don't have the 50 rep yet to be able to comment/ask questions, so my answer is based on what I am seeing above...
To start, it would be helpful if you included what your error/exception is. That said, while you may have a row, you are not checking for null when calling the FieldName field in that row--are you sure you have a non-null value in that field, in that row? If it is null, calling .ToString() will throw an exception...I would suggest something like this:
if (myTable.Rows[i]["FieldName"] != null && myTable.Rows[i]["FieldName"].ToString() != "") //Exception happens here
{
strFieldName = myTable.Rows[i]["FieldName"].ToString();
}
This may or may not be your issue, but either way, checking for null here would be good practice and help avoid invalid operations such as trying to a null instance.

C#: Replace Text Of Blank Items In Listview?

How would I go about about replacing the text of blank items in column 5 of my listView with the word "No"?
I tried this but it threw an InvalidArgument=Value of '4' is not valid for 'index'. error:
foreach (ListViewItem i in listView1.Items)
{
if (i.SubItems[4].Text == " ")
{
i.SubItems[4].Text = i.SubItems[4].Text.Replace(" ", "No");
}
}
The code provided above will get all items within ListView1.Items and check if the sub-item of index 4 and its property Text is equal to   which may result in the described error if the index exceeds the array limit. You may avoid this by making sure that this item is not Nothing.
Example
foreach (ListViewItem i in listView1.Items) //Get all items in listView1.Items
{
if (i.SubItems.Count > 3) //Continue if i.SubItems.Count is more than 3 (The array contains i.SubItems[3] which refers to an item within the 4th column (i.SubItems.Count is not an array. Therefore, it'll start with 1 instead of 0))
{
if (i.SubItems[3].Text == " ") //Continue if i.SubItems[3].Text is equal to  
{
i.SubItems[3].Text = i.SubItems[3].Text.Replace(" ", "No"); //Replace   with No
}
}
}
Notice: Arrays are zero-indexed which means that they start with 0 instead of 1.
Notice: If you only have 4 columns, i.SubItems.Count would be 4 and not 3 because it's a normal int considering that all columns are filled.
Thanks,
I hope you find this helpful :)
If I were you, I'd Use the debugger to figure out what's actually going on.
You can check and see what's actually in i.SubItems, and make sure it's actually what you think it is.
The only possible thing i can think of is maybe you made a typo somewhere or that i.SubItems[4] actually just isn't valid.
maybe you're iterating through some of your list items, but not all of your list items have 5 columns, or maybe some are empty.
Once you get that first error figured out, your logic for replacing the text might work better like this:
if (i.SubItems != null && string.IsNullOrEmpty(i.SubItems[4].Text))
{
i.SubItems[4].Text = "No";
}

I try to clean/reset/clear a list in C# but it gives me InvalidOperationException error

This is a part of an static int method:
int answer = 0;
foreach(int getal in savedNumbers)
{
Console.WriteLine(getal);
answer = answer + getal;
savedNumbers.Clear(); // after this line, I'm getting an error.
}
return answer;
Please help me ... I don't know why savedNumbers.Clear() isn't working at that line.
EDIT: Thanks, problem is solved.
You can't modify the collection while enumerating over it. So, the exception is valid. Clear once you are done with enumerating it.
You can't modify a list while iterating that same list.
You are clearing the list in the middle of enumerating it. You cannot modify the list when you are in the process of enumeration.
int answer = 0;
foreach(int getal in savedNumbers)
{
Console.WriteLine(getal);
answer = answer + getal;
}
savedNumbers.Clear();
return answer;
Msdn says: The foreach statement is used to iterate through the collection to get the desired information, but should not be used to change the contents of the collection to avoid unpredictable side effects
While iterating you cannot change the list/collection, while you can do the same using loop as stated below:
for (int i = 0 i < savedNumbers.Count; i++)
{
var getal = savedNumbers[i];
Console.WriteLine(getal);
answer = answer + getal;
savedNumbers.Clear();
}
You can't modify a collection while enumerating over it. That rule exists even without threading issues considered. From MSDN:
An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and its behavior is undefined.
References:
Modifying .NET Dictionary while Enumerating through it
Why does enumerating through a collection throw an exception but looping through its items does not

Categories

Resources