TommyGunn32
TommyGunn32

Reputation: 934

Unable to dispose and remove controls from control list

thanks for reading.

I have a C#.NET form with buttons that switch controls in a main panel. I didn't have any issues until I upgraded to Visual Studio 2012 and Advanced Installer. Target Framework is 4.0, not 4.5.

When I change controls, I dispose and remove the previous before adding the new one, but I'm getting an error when there aren't any controls yet (ie, when the first one loads).

The original loop crashed with something about iterating while modifying the collection, so now I'm trying to just remove one control after ensuring it's there.

This errors with: Index 0 is out of range.

This all works fine on the dev machine, and it wasn't an issue using the old built-in VS installer.

Any ideas? 4.0 framework issue? Missing reference not being deployed?

Thanks!

panelMain.SuspendLayout();
int control_count = panelMain.Controls.Count;
if (control_count > 1) {
    Log.Write("More than one control found in main panel.", ErrorLevel.Error);
}
if (control_count > 0) {
    Control current_ctrl = panelMain.Controls[0];
    current_ctrl.Dispose();
    panelMain.Controls.Remove(current_ctrl);
}

//foreach (Control ctrl in panelMain.Controls) {
//    ctrl.Dispose();
//    panelMain.Controls.Remove(ctrl);
//}

Upvotes: 0

Views: 329

Answers (2)

jaredbaszler
jaredbaszler

Reputation: 4829

Here is a simple recursive method to dispose of controls if anyone is interested. Using the advice of jmcilhinney above.

NOTE: make sure you read all comments about Visible property and setting it back to true.

    // Start by calling a parent control containing the controls you want to 
    // destroy such as a form, groupbox or panel
    private void DisposeControls(Control ctrl)
    {
        // Make control disappear first to avoid seeing each child control 
        // disappear. This is optional (if you use - make sure you set parent 
        // control's Visible property back to true if you create controls 
        // again)
        ctrl.Visible = false;
        for (int i = ctrl.Controls.Count - 1; i >= 0; i--)
        {
            Control innerCtrl = ctrl.Controls[i];

            if (innerCtrl.Controls.Count > 0)
            {
                // Recurse to drill down through all controls
                this.DisposeControls(innerCtrl);
            }

            innerCtrl.Dispose();
        }
    }

Upvotes: 0

jmcilhinney
jmcilhinney

Reputation: 54457

The issue with the foreach loop that you've commented out is that you cannot add items to or remove items from a collection that you are currently enumerating. That means that if you want to loop through a collection and remove items then you must use a for loop. If you want to remove multiple items then you must loop backwards.

The issue with the second if statement is that disposing a control automatically removes it from its parent's Controls collection. That means that, as soon as you call Dispose on the control, there is no longer an item in the Controls collection so the Remove call fails.

So, the moral of the story is that you should use a for loop, loop backwards and use just Dispose to destroy and remove.

Upvotes: 2

Related Questions