Foreach 在将它们从一种形式复制到另一种形式时不遍历所有控件

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

我正在尝试将所有控件从动态窗体复制到另一个静态声明的窗体。奇怪的是,其中恰好有一半被复制了。代码看起来像这样-

// 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);
}

对于一个特定示例,在循环开始时有 56 个控件,在循环结束时仍有 27 个控件剩余。为了测试,我在第一个循环之后再次添加了相同的 for 循环。这次还剩13个

为什么只添加了一半的控件?为什么 foreach 循环过早退出?

PS:我做这个副本的原因是因为我知道一种捕获动态表单击键的方法。对于静态表单,我可以覆盖 ProcessCmdKey 并捕获击键,但我不知道动态表单有任何等效项

您的假设可能是:

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

只影响一个 ControlCollection,即 this 上的集合。然而,一个控件只能有一个父控件。 Add 实现的内部结构揭示了以下内容:

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

注意 Add 方法如何为父控件集合调用 RemoveInnerList 是一个 ArrayList。每次您将控件添加到另一个表单时,它的大小都会在父级上减小。因此你只处理了一半。

在开始将控件副本添加到 List<Control> 之前,然后将列表中的控件添加到 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);