我坚信在执行ToolStripItemCollection.AddRange时会出错:
我用两个菜单制作了Windows Forms Application,每个菜单包含2个项目。
first menu
second menu
(对不起,但是我没有足够的声誉来发布图像)。
接下来,我实现按钮单击处理程序:
private void button1_Click(object sender, EventArgs e)
{
menu1.DropDownItems.AddRange(menu2.DropDownItems);
}
和System.ArgumentOutOfRangeException被抛出。
我很好奇为什么会发生这种情况,并用ILSpy反编译了ToolStripItemCollection程序集。这是我所看到的:
public void AddRange(ToolStripItemCollection toolStripItems)
{
if (toolStripItems == null)
{
throw new ArgumentNullException("toolStripItems");
}
if (this.IsReadOnly)
{
throw new NotSupportedException(SR.GetString("ToolStripItemCollectionIsReadOnly"));
}
using (new LayoutTransaction(this.owner, this.owner, PropertyNames.Items))
{
int count = toolStripItems.Count;
for (int i = 0; i < count; i++)
{
this.Add(toolStripItems[i]);
}
}
}
没有什么可困扰的。让我们看一下ToolStripItemCollection.Add方法:
public int Add(ToolStripItem value)
{
this.CheckCanAddOrInsertItem(value);
this.SetOwner(value);
int result = base.InnerList.Add(value);
if (this.itemsCollection && this.owner != null)
{
this.owner.OnItemAdded(new ToolStripItemEventArgs(value));
}
return result;
}
最后进入ToolStripItemCollection.SetOwner:
private void SetOwner(ToolStripItem item)
{
if (this.itemsCollection && item != null)
{
if (item.Owner != null)
{
item.Owner.Items.Remove(item);
}
item.SetOwner(this.owner);
if (item.Renderer != null)
{
item.Renderer.InitializeItem(item);
}
}
}
我们可以清楚地看到,for循环删除toolStripItems中的每个步骤。 MSDN就ToolStripItemCollection实现的IList接口发表评论:
在连续元素(例如列表)的集合中,跟随在已删除元素之后的元素将向上移动以占据腾出的位置。如果对集合进行索引,则也会更新所移动元素的索引。
结果,我们最终在错误的索引上访问了toolStripItems中的项目(第二个项目移到了位置0)。我对吗?
最佳答案
不确定100%是什么问题,但是您可以通过将集合转换为数组(需要强制转换)来解决此问题:
menu1.DropDownItems.AddRange(menu2.DropDownItems.Cast<ToolStripItem>().ToArray());
您的版本抛出错误是因为当第一个菜单添加到DropDown集合时,它正在从集合中删除,因此正在迭代,因此出现OutOfRangeException。