protected override void Render(HtmlTextWriter writer)
{
HtmlGenericControl div1 = new HtmlGenericControl("div");
div1.Attributes.Add("class", "modalbox");
if (!ClientVisible)
div1.Attributes.CssStyle.Add("display", "none");
HtmlGenericControl div2 = new HtmlGenericControl("div");
div2.Attributes.Add("class", "modalbox-m1");
HtmlGenericControl div3 = new HtmlGenericControl("div");
div3.Attributes.Add("class", "modalbox-m2");
foreach (Control c in this.Controls)
div3.Controls.Add(c); // exception here
div2.Controls.Add(div3);
div1.Controls.Add(div2);
div1.RenderControl(writer);
}
我无法理解WHO和WHERE更改this.Controls
?
答案 0 :(得分:2)
问题在于,c
,Control
,只有一个Parent ,并且在添加控件时建立了双向关系一个ControlCollection
。除非某些内容被破坏,否则相同的Control 将不会存在于多个ControlCollections中。
因此,当c
添加到div3
时,它首先来自前一个父容器的removes itself - 在这种情况下是c.Parent.Controls
,与{{1}相同的对象正在迭代的。最终结果是修改异常,因为将控件添加到不同的集合会将其从迭代集合中删除..
避免此异常的最简单方法是创建集合的副本,与IEnumerable.ToList
一样。在删除控件时,不会修改独立于ControlCollection的新列表。
this.Controls
但是,在// Note the "ToList()", from LINQ/Enumerable
foreach (Control c in this.Controls.ToList()) {
div3.Controls.Add(c); // exception here
}
内添加控件“相当可疑”并且在很多情况下它会在回发中打破控件。
如果我只想将控件集合包装在代码中并且标记不会影响控件树,那么我将使用类似下面的内容来生成适当的渲染输出而不用< / em>创建新控件或以其他方式修改控件树。 HtmlTextWriter提供了生成相关标记的所有基本方法,即使它可能很乏味。
Render
提示:RenderBeginTag / RenderEndTag作为堆栈工作,通过AddAttribute设置的属性始终适用于下一个RenderBeginTag。
在实践中,我强烈推荐(并经常使用)User Controls,它允许ASCX标记并创建控制树声明。
答案 1 :(得分:1)
通过将this.controls中的控件添加到div3集合,您的代码正在改变它。
我不知道确切的机制,但我怀疑此操作导致c
的重新托管,这会影响this.controls
。
解决方案是将其更改为for循环,该循环通过this.controls
向后工作:
for (int i = this.Controls.Count - 1; i >= 0; i--) {
Control c = this.Controls[i];
div3.Controls.Add(c);
}
答案 2 :(得分:1)
我的最终解决方案:
protected override void CreateChildControls()
{
HtmlGenericControl div1 = new HtmlGenericControl("div");
div1.Attributes.Add("class", "modalbox");
if (!ClientVisible)
div1.Attributes.CssStyle.Add("display", "none");
HtmlGenericControl div2 = new HtmlGenericControl("div");
div2.Attributes.Add("class", "modalbox-m1");
HtmlGenericControl div3 = new HtmlGenericControl("div");
div3.Attributes.Add("class", "modalbox-m2");
div1.Controls.Add(div2);
div2.Controls.Add(div3);
while (Controls.Count != 0)
div3.Controls.Add(Controls[0]);
Controls.Add(div1);
}