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";
}
Related
So, I'm writing a program that is reads table data and puts cells values in a List. I made it, but there is one problem – UsedRange takes all cells on sheet so there is more items then I need and also, when I specify range by ["A:A", Type.Missng] it gives me an exception:
System.ArgumentException: "HRESULT: 0x80070057 (E_INVALIDARG))"
So my question is how to make it correctly?
Code is:
foreach (Excel.Range row in usedRange)
{
for(int i=0; i<lastCell.Row; i++)
{
if (row.Cells[4, i + 1].Value2 != null)
{
personlist.Add(Convert.ToString(row.Cells[4, i + 1].Value2));
}
else { i++; }
}
foreach(var person in personlist) {
Console.WriteLine(person);
}
}
UPD: I need a last used row, that's why I'm using UsedRange. So if there is any alternatives, like, checking if(!=null)? I will gladly try it
Tried to give it specific range, some tries to made a code like here C# - How do I iterate all the rows in Excel._Worksheet?
and here
https://overcoder.net/q/236542/программно-получить-последнюю-заполненную-строку-excel-с-помощью-c
but maybe I'm a dumb one, 'cause there is literally more than one articles about it and non of it works with me
The problem is 'used range' can include empty range (who knows how excel decides that magic number - if you type a letter on some arbitrary row and then delete it Excel can decide that cell is still part of your used range). You want your own custom definition of what a 'usedRange' is, which presumably is the range of non-blank rows. There's two straightforward ways of implementing this yourself (which gives you added control over it should you want to customize it).
You can just filter the list after the fact removing all blank entries. Or you can process the list in reverse, skipping rows till you find one matching your criteria
bool startProcessing = false;
for(int i=lastCell.Row-1; i>=0; i--)
{
if(!startProcessing){//bool is in case you want blank rows in the middle of the file, otherwise check valid row always
//check if valid row
//continue; if not, set startProcessing to true if yes
}
if (row.Cells[4, i + 1].Value2 != null)
{
personlist.Add(Convert.ToString(row.Cells[4, i + 1].Value2));
}
//else { i++; } //this is a bug, will cause a line skip
}
Also, as an aside - when you call i++; in the body of your for loop, it then calls it again in the header of your for loop and i += 2 skipping a row. Use continue; or just remove the else block altogether.
There's probably a way to get a cellRange matching your criteria, but imo doing it yourself can be better - you can ensure it does exactly what you want.
I added a textbox to my form and I'm trying to get the text from it but it comes up with an exception saying
"Input string was not in the correct format."
This is my code:
deleteQuestion = Convert.ToInt32(textBox6.Text);
addQuestion = Convert.ToInt32(textBox7.Text);
listOfQuestions.RemoveAt(deleteQuestion - 1);
foreach (RichTextBox box in boxForQuestions)
{
if (Convert.ToInt32(box.Tag) == deleteQuestion - 1)
{
boxForQuestions.Remove(box);
}
}
In the second part of the code my intention is to delete dynamically added rich text box.
Use Int32.TryParse if you are not in control of what your user types in those textboxes
int deleteQuestion;
if(!Int32.TryParse(textBox6.Text, out deleteQuestion))
{
MessageBox.Show("Not a valid number to delete a question!");
return;
}
int addQuestion;
if(!Int32.TryParse(textBox7.Text, out addQuestion))
{
MessageBox.Show("Not a valid number to add a question!");
return;
}
Of course, the same should be considered for the Tag property used inside the loop but this is set by your code so I presume that it is safe to consider it a valid integer
Another problem in your code is the remove inside the foreach loop. This cannot be done, you cannot change a collection while iterating over it. If you really need to remove an element from that collection you should consider to use a normal for... loop and looping from the last element towards the first one
So I'm making a "type in the correct word to the mixed up word" game to practice some c# as I'm pretty new to it. I've got a List< List < string >> that adds three lists: mixedwordslist, correctwortslist and the inputlist that I've just called "TheList". When I loop through the correctvalue to check if the user input is correct, I set the score to += 1. After that I want to add the input to the inputlist, thus not getting just the newest input.
I've tried to change every List to a Dictionary, so that I could just insert the index, and add it everytime it looped through an item. That worked, but when I wanted to output every value, it got too complicated and so I just went back to leaving my lists as List and not Dictionary.
Here's my code:
foreach (string mixedvalue in mixedword.mixedwordslist)
{
Console.Write($"\n{mixedvalue}:\t");
input = Console.ReadLine();
foreach (string correctvalue in correctword.correctwordslist)
{
if (input.Equals(correctvalue))
{
score += 1;
}
else
{
continue;
}
}
inputlist.inputlist.Add(input);
}
This is a perfect situation for LINQ.
So that you're not modifying a list while you're cycling through it, you'll so a select on the list. Assuming your lists are just List you should be able to replace your inner foreach loop. It looks like you might have some unnecessary nested properties but you could do something like this instead.
First check if score needs update.
if(correctwordslist.Where(x=>x == input).Any())
{
score += 1;
}
Then add to the input list if it hasn't already been tried.
if(!inputlist.Where(x=>x==input).Any())
inputlist.Add(input);
I have the following enum declared:
public enum EtcMethod
{
ACCORD,
COROLLA,
COROLLA_S,
CAMRY,
CIVIC
}
On my form, I have a handful of controls with their Tag property set:
myControl1.Tag = "ACCORD";
myControl2.Tag = "COROLLA";
myControl3.Tag = "CIVIC COROLLA_S CAMRY";
Then I'm checking the controls' tags in a loop to see if any of the values are found:
private void HideControls(EtcMethod etcMethod, LayoutControlGroup lcg)
{
foreach (BaseLayoutItem ctl in lcg.Items)
{
if (ctl.GetType() == typeof (LayoutControlItem))
{
LayoutControlItem item = (LayoutControlItem)ctl;
if (item.Tag.ToString().IndexOf(etcMethod.ToString()) >= 0)
item.Visibility = LayoutVisibility.Always;
else
item.Visibility = LayoutVisibility.Never;
}
}
}
But the problem with this is, for example, if etcMethod is COROLLA and item.Tag.ToString() is "COROLLA_S" that'll erroneously pass the check.
How can I make sure that it'll find an exact match instead of a "partial" match? In other words, I would like it to behave as if you checked off the "Match whole word" option using Visual Studio's Find feature.
The only solution I could think of would be to check the value of the character at etcMethod.Lenght+1 and see if it's a space (indicating the beginning of another enum value) or if that position even exists (indicating the end of the tag), but that seems particularly sloppy.
Why don't you Split it and use Contains ?
if (item.Tag.ToString().Split().Contains(etcMethod.ToString()))
This will first split your Tag on space, if it hasn't space it just turn it into a string array, then using Contains on array will look for exact match.
This may be one solution:
if (item.Tag.ToString() + " ").IndexOf(etcMethod.ToString() + " ") >= 0)
I created a Listview control with 8 columns. When I need to retrieve text from subitem of Item, I use the following code:
foreach (ListViewItem item in listViewStatus.Items)
{
if (item.Tag == f)
{
/* Use locking to synchronise across mutilple thread calls. */
lock (_lockObject)
{
item.SubItems[6].Text = Status;
}
break;
}
}
it shows an exception. But when I replace item.SubItems[6].Text with item.SubItems[5].Text it works. How can I fix this?
Obviously you have at most 6 columns in SubItems
If you've only created 6, then the values are 0-5; meaning 6 is invalid.
This is a classic "off-by-one" error scenario.
Indicies come in two flavors: Zero-based, and One-based. C# is a zero-based index language. I assume you're either learning a language for the first time, or learning a zero-based language for the first time - Otherwise, I'm missing the point of the question, and I apologize. :)
See Wikipedia, Off-By-One Error: http://en.wikipedia.org/wiki/Off-by-one_error
The ArgumentOutOfRange exception is thrown by the runtime when it realizes that there is no 7th item in the list. This kind of error cannot be caught at compile time (without using heuristics), due to the fact that the list may contain any number of values at any time
TLRD;
Zero-Based (C#):
... = myList[0]; // This is a zero-based indexer.
... = myList[1];
... = myList[2];
... = myList[3];
... = myList[4];
... = myList[5]; // This is the 6th item, although the index is 5.
One-Based (some other language):
... = myList[1]; // This is a one-based indexer.
... = myList[2];
... = myList[3];
... = myList[4];
... = myList[5];
... = myList[6]; // This is the 6th item, and the index is 6.
SubItems[6]
6 there represents the column index not the index of a row.