Why controls do not want to get removed?

I am trying to remove all the controls that are contained in my winform panel but they simply do not want to get removed - some of them are removed and some of them not. I have tried 2 approaches already and nothing:

  1. foreach

    foreach (Control controlEntry in this.contentsPanel.Controls)
    {
        this.contentsPanel.Controls.Remove(controlEntry);
    }
    
  2. for

    for (int i = 0; i < this.contentsPanel.Controls.Count; i++)
    {
        this.contentsPanel.Controls.RemoveAt(i);
    }
    

Why is this happening ?


You have to watch out for code like this, removing controls from their container like this produces an unrecoverable resource leak. Controls.Remove/At(), or the Controls.Clear() method as suggested by other posters, removes the control from the collection and re-hosts it to the "parking window". An otherwise invisible window where the native window can find a hospitable home without having to be destroyed. Ready to be re-hosted on another parent.

Which is the trap, you typically don't move it to another parent. The control will continue to survive on the parking window, consuming native Windows resources. The garbage collector cannot recover these resources. Eventually your program will crash when Windows refuses to provide more windows to your process. The exception message will say "Error creating handle".

Instead, you must dispose the control. Which also automatically removes the control from its parent. The proper code is:

 while (contentsPanel.Controls.Count > 0) contentsPanel.Controls[0].Dispose();

Or iterate backwards if you find this a bit too bizarre looking.


Each time you remove control from collection, the collection changes. When you remove 1st element of Controls, 2nd element becomes 1st, so when you proceed to delete 2nd control, you are in fact removing 3rd element from original collection (skipping 2nd element).

If you want to remove all controls contained in collection, use this.contentsPanel.Controls.Clear(). If you want to remove controls by their indices in ControlCollection, first select controls to remove to separate list or array and then remove them.


If you want to remove them all then just do

this.contentsPanel.Controls.Clear()

The foreach will fail because you are changing the collection, which breaks the iterator.

The for fails because you are only removing every other item; consider: i=0, you remove the zeroth item. Now the item that was item 1 is item 0 - so when you remove item 1 (next loop iteration) you have jumped one.

Short version: use Clear():

contentsPanel.Controls.Clear();

Longer version: iterate backwards:

for(int i=contentsPanel.Controls.Count-1; i>=0;i--) {
   contentsPanel.Controls.RemoveAt(i);
}

The first (Clear) is simpler.