C# Weird Bug when trying to remove Controls from Group Box - c#

I am currently facing a really weird issue. I simply want to remove all controls from a group box, but it just does not remove all controls. It really seems like a bug on Microsoft's end right now. I tried many different techniques of removing these controls, but none of them worked. I have two other methods where I am removing just one Control at a time (and no, I cannot call that in a loop for all my controls) and there it works fine. I have no idea what the issue could be. Hopefully someone knows a way around this.
foreach (Control c in fieldBox.Controls) // this does not work, it only removes my labels (I have one txt and one lbl)
fieldBox.Controls.Remove(c);
for (int i = 0; i < fieldBox.Controls.Count; i++) // this does not work either
fieldBox.Controls.Remove(fieldBox.Controls[i]);
for (int i = 0; i < fieldBox.Controls.Count; i++) // still no success
fieldBox.Controls.RemoveAt(i);
for (int i = 0; i < fieldBox.Controls.Count; i++) // nope
fieldBox.Controls.RemoveByKey(fieldBox.Controls[i].Name);
foreach (Control c in fieldBox.Controls) // my final answer, but the outcome did not change
fieldBox.Controls.RemoveByKey(c.Name);

Try decreasing the counter and removing controls
for (int i = fieldBox.Controls.Count - 1; i >= 0; i--) // hopefully successful
fieldBox.Controls.RemoveAt(i);

Related

iterate through rows and cells using for loop in c# Selenium

I have already checked many answers but all are using a foreach loop to iterate through rows. I want to use a for loop.
Code:
IWebElement NtTable = driver.FindElement(By.Id("nt-item-table"));
IReadOnlyCollection<IWebElement> TableRows = NtTable.FindElements(By.TagName("tr")).ToList();
for (int i = 0; i <= TableRows.Count; i++)
{
//driver.FindElement(TableRows[i])....
//Tablows.get(i)....
}
I tried above commented 2 lines to get text of particular TD from particular TR but seems not getting any property after press (.). Above seems fine if I use Java but not in C#.
There are several issues.
You don't need to chain the .FindElement() calls. It's more efficient to just get the TRs in one search, e.g. by CSS selector #nt-item-table tr.
You are calling .ToList() after the .FindElements() call which isn't necessary and won't work. It shows an error in the IDE.
You are iterating to <= TableRows.Count when you only need <. The index starts at 0.
You can't access elements in the IReadOnlyCollection using array notation, e.g. TableRows[i]. You need to use LINQ and ElementAt(i).
You already have found the TR elements, statements like driver.FindElement(TableRows[i]).... make no sense.
Tablows is not a variable name that you have defined. The variable is TableRows.
IReadOnlyCollection<IWebElement> TableRows = Driver.FindElements(By.CssSelector("#nt-item-table tr"));
for (int i = 0; i < TableRows.Count; i++)
{
// do something with TableRows.ElementAt(i);
}
You really should spend some time reading some Selenium and basic C# programming tutorials, syntax references, etc. It will help you avoid a lot of these issues.
I changed the variables to start lowercase (camelcase) and have you tried this. Since you already have a list of tr elements which have child elements (td)
IWebElement ntTable = driver.FindElement(By.Id("nt-item-table"));
IReadOnlyCollection<IWebElement> tableRows = ntTable.FindElements(By.TagName("tr")).ToList();
for (int i = 0; i <= tableRows.Count; i++)
{
var tdCollection = tableRows[i].FindElements(By.TagName("td"));
for (int c = 0; c <= tdCollection.Count; c++)
{
string column = tdCollection[c].Text;
}
}
I would prefer foreach though. Because you do not need index int's then.

c# for loop is entering without meeting its condition

So, I have this for loop:
double spec = 0, tot = 0;
for (int i = 0; i < omega_algo.Length; i++)
{
if (omega_algo[i] > 0)
spec = Math.Sqrt(omega_algo[i]);
else
spec = 0;
tot += spec;
}
Where myArray.Length = 50.
I get an IndexOutOfRangeException while debugging and see that i is 50.
So, the for loop is entering when it shouldn't ( i < myArray.Length is false )!
This exception only occurrs ocasionally, which makes it even more weird.
Does someone have an explanation/fix for this? Am I missing something or could this be a weird Visual Studio bug?
EDIT:
I've edited the for loop to show the code.
No i is being incremented and omega_algo array is not changing at all.
EDIT:
Based on the comments below, I wrote a sample app, and your code should work as is.
If your array really does have a length of 50, then the value of i will never be 50. The only way this would be possible is if you are changing the value of i inside the loop.
Can you provide more code to show some context of how/where this is being used? How the array is being defined etc?
Your code should work if executed on a single thread. Do you have any thread or asynchrone jobs that are editing the array?
If so, just lock the array before accessing it and before editing it.
lock(myArray)
{
for (int i = 0; i < myArray.Length; i++)
{
int someVar = myArray[i]; //this is where exception is thrown when i=50
}
}
EDIT:
Since omega_algo array is not changing at all, this is not a threading issue.

C# ListView - Programatically editing column entries

I'm using a ListView with two columns.
To add new items (into column zero) I'm using:
listView1.Items.Add("Hello")
This results in Hello being present in the column with the lowest index.
However, I'd also like to add in line numbers.
I'm trying this with:
for (int c = 0; c < listView1.Items.Count; c++)
{
listView1.Items[c].SubItems.Clear();
listView1.Items[c].SubItems.Add(c.ToString());
}
The problem, I believe, lies with the main item(s) being cleared even though I'm just attemping to clear() the subitems (i.e. the entry in the second column).
So essentially my question is:
How do I individually edit column entries to be able to display the lines/row numbers?
First item (index 0) in SubItems is actually main item in left column.
If you already added sub item like this listViewItem.SubItems.Add(string.Empty); then you can edit that sub item like this:
for (int c = 0; c < listView1.Items.Count; c++)
{
listView1.Items[c].SubItems[1].Text = c.ToString();
}
I may have solved it...
It may be that once a SubItem is added, the main item is moved to SubItem[0].
The following code seems to be working for me, but I'm not sure if a better way exists.
for (int c = 0; c < listView1.Items.Count; c++)
{
listView1.Items[c].SubItems[0].Text = listView1.Items[c].Text;
listView1.Items[c].SubItems.Add(c.ToString());
listView1.Items[c].SubItems[1].Text = c.ToString();
}

Row Index provided is out of range, even after check

My current code:
Remove()
{
for (int i = 0; i < ConGridView.RowCount; i++)
{
if (ConGridView.Rows[i].Cells[0].Value.ToString() == Address)
{
ConGridView.Rows.RemoveAt(i);
break;
}
}
}
So what I am trying to call the remove function every time a client disconnect. the function will remove the connection address from the datagridview. It works well when clients are disconnection one by one. However, if 100 connections gets dropped and it tries to remove 100 connections in less than a second, than it errors out saying "Row Index provided is out of range". How should I check for that ?
So far I've tried:
Try, catch.
if (ConGridView.Rows[i] != null), if (i < ConGridView.RowCount)
None of it seem to work so far. I've also got results using (i < ConGridView.RowCount) where i is 26 while RowCount is 24, but the remove at function still activates..
Any idea on this ?
You can't do this. Your code loops through all the rows in ConGridView, but it deletes them as you do. Therefore, at some point you will try to access an item you have deleted, which will cause the error you described.
Probably the best approach it to iterate through the rows in reverse order. This way, deleting a row at the end won't affect when you access rows at the start.
The problem is you initialise your for loop with the current count of rows and then start removing those same rows from the datagridview. At some point your for loop will try to remove a row at an index that is greater than the number of rows left.
Try this instead:
for (int i = ConGridView.RowCount - 1; i >= 0; i--)
{
if (ConGridView.Rows[i].Cells[0].Value.ToString() == Address)
{
ConGridView.Rows.RemoveAt(i);
break;
}
}
why dont you get the total count to a separate variable and then iterate
Remove()
{
int totalConnections = ConGridView.RowCount;
for (int i = 0; i < totalConnections ; i++)
{
if (ConGridView.Rows[i].Cells[0].Value.ToString() == Address)
{
ConGridView.Rows.RemoveAt(i);
break;
}
}
}
This issue is becuase you are modifying the collection your are iterating over. It will be better if you use a temporary array and two loops to remove your entries.
Remove()
// You can use an array/list or whatever you want below.
Collection<DataGridViewRow> rowsToDelete = new Collection<DataGridViewRow>();
for (int i = 0; i < ConGridView.RowCount; i++)
{
if (ConGridView.Rows[i].Cells[0].Value.ToString() == Address)
{
rowsToDelete.Add(ConGridView.Rows[i]);
break;
}
}
// now remove the marked entries.
foreach(DataGridViewRow deletedRow in rowsToDelete)
{
ConGridView.Rows.Remove(deletedRow);
}
When you remove an item from an array, it is reconstructed; shifting the remaining elements up by one to remove the gap of the index you have removed.
1. guybrush threepwood
2. murray
3. elaine
4. Jimmy Gibbs Jr.
If you remove 2. item in here; it becomes this:
1. guybrush threepwood
2. elaine
3. Jimmy Gibbs Jr.
When you are iterating, imagine:
for (int i = 0; i < myArray.Count; i++)
{
if (i == 2) myArray.RemoveAt(i);
}
While running this, when i = 3, the element at 3 has changed, you expect it to be 'elaine' but it is 'Jimmy Gibbs Jr.'. One way to fix this is decrease i by one if we delete it, making sure that i refers to correct value.
for (int i = 0; i < myArray.Count; i++)
{
if (i == 2)
{
myArray.RemoveAt(i);
i--;
}
}
I would go for LINQ in this case, though, everything is easier with that.
myArray.RemoveAll(x => x == "murray");
I've tried all the suggestions posted by everyone here, however, the error was still there.
I've solved the problem using a different way... I've switched to TreeNodeView since that's what I was going to use ultimately. Now I can remove as many connection as i want with:
For each(TreeNode TN in ConTreeView)
{
ConTreeView.Nodes.Remove(TN);
}

C# ListView Problem Adding Items

So, here's my question: Why won't the code in the first snippet work when the second one works fine. Also, I have set the view property to details. I've read all over how to add lvi's to the listview, and it fails every time... except for then I do it manually.
So, this doesn't work...
// Iterating through the rows...
for (int x = 0; x < numRows; x++) {
row = new List<string>();
// Iterating through the cols...
for (int y = 0; y < numCols; y++) {
row.Add(data[y][x]);
}
lv.Items.Add(new ListViewItem(row.ToArray()));
}
But this will work:
lv.Items.Add(new ListViewItem("foo"));
row.Add(data[y][x]) seems suspicious. Why do you access the data in column-first order but iterate in row-first order? Also, make sure the type of row (you didn't tell us this) is actually List<string>.
The ListViewItem is looking for a String[] try casting row.ToArray() to a String[].

Categories

Resources