Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

My controls are not being disposed correctly?

I have the following method:

    public static void Disposer(Control.ControlCollection controls)
    {
        foreach (Control c in controls)
        {
            if (c.HasChildren)
                Disposer(c.Controls);

            if ((c is UltraNumericEditor)
                || (c is UltraComboEditor)
                || (c is UltraTextEditor)
                || (c is UltraDateTimeEditor)
                || (c is UltraCheckEditor)
                || (c is UltraGrid)
                || (c is UltraStatusBar))
            {
                c.Dispose();
                var x = c.IsDiposed; // this is true!
            }

        }
    }

Then I called it with this:

   [STAThread]
    static void Main()
    {
        Test forma = new Test();
        forma.Controls.Add(new UltraStatusBar());
        forma.Controls.Add(new UltraStatusBar());
        forma.Controls.Add(new UltraNumericEditor());
        forma.Controls.Add(new UltraComboEditor());
        forma.Controls.Add(new UltraTextEditor());
        forma.Controls.Add(new UltraTextEditor());
        forma.Controls.Add(new UltraDateTimeEditor());
        forma.Controls.Add(new UltraTimeZoneEditor());
        forma.Controls.Add(new UltraGrid());

        Disposer(forma.Controls);

        foreach (Control control in forma.Controls)
        {
            if (control.IsDisposed)//this is false now!
            {
                Debug.Write(control.Name + " was disposed");
            }
        }
    }

My question is, why inside my Disposer method my controls are becoming disposed, but when I check in the main method is returning false?? By the way the "Test" object is just a simple class that inherits from UserControl Thanks, regards.

like image 673
hyeomans Avatar asked Jun 23 '11 16:06

hyeomans


1 Answers

There is a bug in the Control.ControlCollection class. It is missing the code to generate an InvalidOperationException that other collection classes generate when you modify the collection in a foreach loop.

Which you are doing, calling Dispose() removes a control from the Controls collection. In effect, you only dispose every other control.

A better way to dispose the controls, one that drives the point home, is:

while (controls.Count > 0) controls[0].Dispose();

although it is hard not to use a for() loop that works backwards. This code is almost always unnecessary, Winforms automatically disposes controls. And nothing needs disposed the control's CreateControl() method hasn't been called yet. Which doesn't happen until the container form has had its Show() method called and completed. Only dispose controls yourself when you call the Controls.Remove() or Controls.Clear() method.

like image 174
Hans Passant Avatar answered Oct 19 '22 00:10

Hans Passant