2

I have spent hours trying to understand what is the problem in my coding but without any much result. Hence thought of posting here for an explanation

In my UI design, I have first row of <<checkbox, textbox, textbox>> in this order. And depending on the number of rows of result returned, I will dynamically create the same number of rows of checkbox and textboxes.

However when I try to remove the redundant rows, leaving only row 1 intact, I noticed that only some controls are being removed.

For e.g

Before deleted:

checkbox0 textbox0 tb0

checkbox1 textbox1 tb1

checkbox2 textbox2 tb2

After executing

checkbox0 textbox0 tb0

--------- -------- tb1

checkbox2 textbox2 ---

My code for removing is as below:

foreach (Control c in panel1.Controls)
{                
  lastChar = c.Name[c.Name.Length - 1];
  lastValue = (int)Char.GetNumericValue(lastChar);
  MessageBox.Show("second " + c.Name);

  if (lastValue > 0 && lastValue < count)
  {
    panel1.Controls.Remove(c);
    c.Dispose();
  }
 }

Rightfully foreach will run through all the controls within the panel1. But i noticed that once the Remove statement is in, the whole operation went haywire.

Zero Piraeus
  • 56,143
  • 27
  • 150
  • 160

2 Answers2

5

You can not add or remove items into/from a IEnumerable inside a foreach loop. Instead try using a for loop. Check this. Actually the exception you are receiving should be telling you this.

for (int i = 0; i < panel1.Controls.Count; i++)
{                
  Control c = panel1.Controls[i];
  lastChar = c.Name[c.Name.Length - 1];
  lastValue = (int)Char.GetNumericValue(lastChar);
  MessageBox.Show("second " + c.Name);

  if (lastValue > 0 && lastValue < count)
  {
    panel1.Controls.Remove(c);
    c.Dispose();
    i--;
  }
 }
Community
  • 1
  • 1
Mehmet Ataş
  • 11,081
  • 6
  • 51
  • 78
0

You can shorten @Adi's code slightly with:

        for (int i = panel1.Controls.Count - 1; i >= 0; i--)
        {
            Control c = panel1.Controls[i];
            lastValue = (int)Char.GetNumericValue(c.Name, c.Name.Length - 1);
            if (lastValue > 0 && lastValue < count)
            {
                c.Dispose();
            }
        }

Note the overload of GetNumericValue() to directly get your desired character value, and you only need to dispose of the control as this will automatically remove it from the container.

Idle_Mind
  • 38,363
  • 3
  • 29
  • 40
  • I'm pretty sure your last statement is incorrect. Have you tested it or can you give a reference to where this behavior is documented? – Adi Lester May 25 '13 at 21:58
  • 1
    Tested it countless times in real-world apps. I don't believe it's documented anywhere though. See this [answer](http://stackoverflow.com/a/2013911/2330053). – Idle_Mind May 26 '13 at 00:02
  • Thanks Guys~!! You guys rocks!! – user2420800 May 26 '13 at 00:18
  • But I just cannot understand one thing, why couldn't I iterate through all the controls when Remove function is used? – user2420800 May 26 '13 at 00:21
  • Simply because you can't modify the collection that you are enumerating with a `foreach` construct. When you Remove() the control that modifies the Controls() collection which you are iterating over. Note that all the solutions presented are using an "indexed" `for` loop, not a `foreach`. – Idle_Mind May 26 '13 at 01:36
  • @Idle_Mind That's nice to know, thanks. I'd still include the `Remove` statement just for clarity though. – Adi Lester May 26 '13 at 06:44