Jim Chen
Jim Chen

Reputation: 36

Remove all buttons from panel

I am trying to remove all buttons from panel. somehow it remove only half with my code. i do not know why. this is in c# windows form. can someone explain please. thank you. code as follows: Added using

        for(int ii=1; ii<=6; ii++)
        {
            for(int jj=1; jj<=5; jj++)
            {
                Button b = new Button();
                b.TabStop = false;
                b.Width = 146;
                b.Height = 91;
                b.Click += new EventHandler(b_Click);
                panel.Controls.Add(b);
            }
        }

Remove using

        foreach (Control c in panel.Controls)
        {
            c.Click -= new EventHandler(this.b_Click);
            panel.Controls.Remove(c);
            c.Dispose();
        }

Upvotes: 1

Views: 5155

Answers (4)

Mitja
Mitja

Reputation: 873

Your list of controls is iterating to the half because the iterator increase while the amount of items are decrease. In the middle of the (internal) index of your Control-List is bigger than the amount of items.

Save the list of items first:

List<Button> buttons = panel.Controls.OfType<Button>().ToList();
foreach (Button btn in buttons)
{
    btn.Click -= new EventHandler(this.b_Click); //It's unnecessary
    panel.Controls.Remove(btn);
    btn.Dispose();
}

edit: Why do you remove the Click-Event, if you dispose the button? After Disposing, the events are cleared and the button could not be used either.´

If you want a 1 line solution, you could only use Dispose. It will remove the buttons automatically from the panel an clear all events etc.

panel.Controls.OfType<Button>().ToList().ForEach(btn => btn.Dispose());

Upvotes: 6

Chris
Chris

Reputation: 5514

You are not allowed to modify a collection (Controls) while iterating it, so that code shouldn't work.

Try simply:

panel.Controls.Clear();

You'll be fine without the call to Dispose.

Edit: if you do only want to remove all Button's (and have other and possibly nested controls), you can do something like this:

private void FindControls<T>( List<T> list, Control parent ) where T : Control
{
    foreach( Control c in parent.Controls )
    {
        if( c is T )
            list.Add( (T)c );
        FindControls( list, c );
    }
}

// and use like so:
var list = new List<Button>();
FindControls( list, this );
foreach( var b in list )
    b.Parent.Controls.Remove( b );

Upvotes: 0

RFerwerda
RFerwerda

Reputation: 1277

foreach (Control c in panel1.Controls.OfType<Button>().ToList())
{
    panel1.Controls.Remove(c);
    c.Dispose();
}

Upvotes: 2

Jeffrey Wieder
Jeffrey Wieder

Reputation: 2376

Unfortunately the compiler allows this sort of thing, but usually results in a run-time exception. You need to iterate over a collection that is not being modified.

    List<Control> ctrls = new List<Control>(panel.Controls)
    foreach (Control c in ctrls)
    {
        if(c is Button)
        {
             c.Click -= new EventHandler(this.b_Click);
             panel.Controls.Remove(c);
            c.Dispose();
        }
    }

Upvotes: 0

Related Questions