Pavan Manjunath
Pavan Manjunath

Reputation: 28535

Foreach not looping through all controls while copying them from one form to another

I am trying to copy all controls from a dynamic form to another statically declared form. Curiously exactly half of them are getting copied. The code looks like this-

// Constructor of static form
public ApplicationForm(dynamic form)
{
        // Add all controls from the dynamic form to the Application form
        Console.WriteLine("I have total of {0} controls\n", form.Controls.Count);
        int i = 0;
        foreach (Control c in form.Controls)
        {
            i++;
            this.Controls.Add(c);
            Console.WriteLine(" Number of controls rem {1}\n",
                              form.Controls.Count);
        }
        Console.WriteLine("I added a total of {0} controls and still have {1}\n",i,     
                           form.Controls.Count);
}

For one particular example, there were 56 controls at the beginning of the loop and there were 27 still remaining at the completion of the loop. And just to test I added the same for loop again after the first one. This time there were 13 remaining.

Why are only half of the controls getting added? Why is the foreach loop exiting prematurely?

PS: I reason I am doing this copy is because I do know a way of capturing keystrokes for a dynamic form. For a static form, I can override ProcessCmdKey and trap keystrokes but I dont know of any equivalent for dynamic forms

Upvotes: 1

Views: 445

Answers (1)

rene
rene

Reputation: 42443

Your assumption probably is that this:

    foreach (Control c in form.Controls)
    {
        this.Controls.Add(c);
    }

only affects ONE ControlColection, namely the collection on this. A control however can only have ONE parent. The internals of the Add implementation reveals the following:

public virtual void Add(Control value)
{
    // skipped stuff
    if (value.parent != null)
    {
        value.parent.Controls.Remove(value);
    }
    base.InnerList.Add(value);
    // many more
 }

Notice how the Add method calls Remove for the parent controlcollection. The InnerList is an ArrayList. It's size gets reduced on the parent every time you add a control to the other form. Hence you only process half of them.

Before you start adding the Controls copy to a List<Control> first and then add the controls from the list to the ApplicationForm.

    // copy controls to list
    var list = new List<Control>();
    foreach (Control c in form.Controls)
    {
        list.Add(c);
    }
    Console.WriteLine("I have total of {0} controls\n", form.Controls.Count);
    int i = 0;
    // iterate over list
    foreach (Control c in list)
    {
        i++;
        this.Controls.Add(c);
        Console.WriteLine(" Number of controls rem {1}\n",
                          form.Controls.Count);
    }
    Console.WriteLine("I added a total of {0} controls and still have {1}\n",i,     
                       form.Controls.Count);

Upvotes: 2

Related Questions