我坚信在实施ToolStripItemCollection.AddRange时是错误的:
我使用两个菜单制作了Windows窗体应用程序,每个菜单包含两个项目。
(对不起,但我没有足够的声誉来发布图片)。
接下来,我实现按钮点击处理程序:
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);
}
}
}
我们可以清楚地看到,在每一步中, toolStripItems 中的循环删除项目。 MSDN对ToolStripItemCollection实现的IList接口发表了评论: 在连续元素(如列表)的集合中,删除元素后面的元素向上移动以占据空出的位置。如果集合已编制索引,则还会更新已移动元素的索引。。 结果,我们最终在错误的索引上访问toolStripItems中的项目(第二个项目转移到位置0)。我是对的吗?
答案 0 :(得分:1)
不是100%确定问题是什么,但您可以通过将集合转换为数组(需要强制转换)来解决此问题:
menu1.DropDownItems.AddRange(menu2.DropDownItems.Cast<ToolStripItem>().ToArray());
你的版本引发错误是因为当第一个菜单被添加到DropDown集合时,它会从迭代的集合中删除,因此OutOfRangeException。