C# Foreach在将所有控件从一个窗体复制到另一个窗体时不循环所有控件

C# Foreach在将所有控件从一个窗体复制到另一个窗体时不循环所有控件,c#,forms,foreach,controls,C#,Forms,Foreach,Controls,我试图将所有控件从一个动态窗体复制到另一个静态声明的窗体。奇怪的是,其中有一半正被复制。代码如下所示- // 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

我试图将所有控件从一个动态窗体复制到另一个静态声明的窗体。奇怪的是,其中有一半正被复制。代码如下所示-

// 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,即此上的集合。但是,控件只能有一个父控件。
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
方法如何调用父控件集合的
Remove
InnerList
是一个
ArrayList
。每次向另一个窗体添加控件时,父窗体上的大小都会减小。因此,您只处理其中的一半

在开始添加控件之前,请先复制到
列表
,然后将列表中的控件添加到应用程序窗体

    // 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);
//将控件复制到列表
var list=新列表();
foreach(form.Controls中的控件c)
{
增加(c)项;
}
WriteLine(“我总共有{0}个控件,\n”,form.controls.Count);
int i=0;
//遍历列表
foreach(列表中的控件c)
{
i++;
本.控件.添加(c);
WriteLine(“控件数rem{1}\n”,
窗体、控件、计数);
}
WriteLine(“我总共添加了{0}个控件,但仍然有{1}\n”,I,
窗体、控件、计数);

我期待一些枚举器的魔力。您是否可以尝试先将所有控件添加到列表中,然后对该列表进行迭代以将它们添加到applicationform中?您是只查找顶级控件还是查找所有控件?在这种情况下,您还需要遍历child。告诉我我的看法是否正确。我可以发布一些代码。是的,@rene是正确的。您正在访问集合并同时更改它(通过更改控件的父级)。请试着把它放在一个列表中并检查。请让我们知道它是否有效。@rene你是对的!如果我使用中间列表,它会起作用。你能详细解释一下,让我接受吗?另外,非常想知道第一级控件的子控件会发生什么情况?我的意思是如果我复制最上面的控件就足够了,对吗?所有的孩子都会自动跟随父母移动,对吗?我看不出你在哪里做任何复制。我只看到您正在移动控件,同时也在修改枚举集合,这是不可能的。我仍然对移动的元素数量的一半感到困惑。我可以在for循环外看到源窗体上的正计数。如果是这样,为什么循环会退出?您还可以介绍一下子控件吗?ArrayList的长度会随着每次添加/删除而减小。假设只有2个控件,在处理第一个控件之后,数组的长度现在是1,for循环计数器增加到1,并检查计数器是否小于长度,这是false,因此循环存在。我假设您移动/复制的控件的子控件不受影响。它们位于其父级的控件集合中,而不是表单。@PavanManjunath为避免此类混淆,如果在枚举过程中修改了基础集合,则枚举器实现通常会引发异常。有趣的是,
ControlsCollection
的一个似乎是专门为不这样做而设计的(基类实现遵循抛出模式)。只使用
while(form.Controls.Any()){this.Controls.Add(form.Controls.First();}不是更简单吗
?当然@corey这也是一种方法,但这可能比我的解决方案更令人困惑。如果这是一个问题,你的解决方案可能会更节省内存。。。。