System.ArgumentOutOfRangeException Toolstrip menu

1.3k views Asked by At

I am getting the below exception randomly. The toolstrip menu is created dynamically.

System.ArgumentOutOfRangeException - Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
at System.Collections.ArrayList.get_Item(Int32 index)
at System.Windows.Forms.Layout.ArrangedElementCollection.get_Item(Int32 index)
at System.Windows.Forms.Layout.FlowLayout.xLayoutRow(ContainerProxy containerProxy, ElementProxy elementProxy, Int32 startIndex, Int32 endIndex, Rectangle rowBounds, Int32& breakIndex, Boolean measureOnly)
at System.Windows.Forms.Layout.FlowLayout.xLayout(IArrangedElement container, Rectangle displayRect, Boolean measureOnly)
at System.Windows.Forms.Layout.FlowLayout.GetPreferredSize(IArrangedElement container, Size proposedConstraints)
at System.Windows.Forms.ToolStripDropDownMenu.ToolStripDropDownLayoutEngine.GetPreferredSize(IArrangedElement container, Size proposedConstraints)
at System.Windows.Forms.ToolStrip.GetPreferredSizeCore(Size proposedSize)
at System.Windows.Forms.Control.GetPreferredSize(Size proposedSize)
at System.Windows.Forms.ToolStripDropDown.GetSuggestedSize()
at System.Windows.Forms.ToolStripDropDown.AdjustSize()
at System.Windows.Forms.ToolStripDropDownMenu.OnLayout(LayoutEventArgs e)
at System.Windows.Forms.Control.PerformLayout(LayoutEventArgs args)
at System.Windows.Forms.Control.System.Windows.Forms.Layout.IArrangedElement.PerformLayout(IArrangedElement affectedElement, String affectedProperty)
at System.Windows.Forms.ToolStripItem.InvalidateItemLayout(String affectedProperty, Boolean invalidatePainting)
at System.Windows.Forms.ToolStripDropDownItem.OnRightToLeftChanged(EventArgs e)
at System.Windows.Forms.ToolStripItem.OnOwnerChanged(EventArgs e)
at System.Windows.Forms.ToolStripMenuItem.OnOwnerChanged(EventArgs e)
at System.Windows.Forms.ToolStripItem.SetOwner(ToolStrip newOwner)
at System.Windows.Forms.ToolStripItemCollection.SetOwner(ToolStripItem item)
at System.Windows.Forms.ToolStripItemCollection.Add(ToolStripItem value)

The exception is happening in the following method . It happens when an item is added to the mnuRoot. This method is invoked on the on the right click of selected items.

private static void BuildMenu(ToolStripMenuItem root, XMLSerItem mnuItem, ToolStrip mnuRoot, Dictionary<string, Image> dctIcons, CustomMenuClickHandler dlgEventHandler, ToolStripMenuItem mnuAddAfter, bool bHideDisabled)
        {
            if(root == null)
            {
                // Try to find an existing menu item
                ToolStripItem mnuMerge = FindMenuItem( mnuRoot.Items, mnuItem );
                if(mnuMerge == null)
                {
                    lock( mnuRoot.Items )
                    {
                            if (mnuAddAfter == null)
                            {             
                                mnuRoot.Items.Add(item);
                            }
                            else
                            {
                                mnuRoot.Items.Insert(mnuRoot.Items.IndexOf(mnuAddAfter), item);
                            }

                    }
                }
                else
                {
                    // Use a reference to the found item
                    item = mnuMerge;
                }
            }
            else
            {
                // Try to find an existing menu item
                ToolStripItem mnuMerge = FindMenuItem( root.DropDownItems, mnuItem );
                if(mnuMerge == null)
                {
                    lock( root.DropDownItems )
                    {
                        // Add the menu item to the root item
                        root.DropDownItems.Add( item );
                    }
                }
                else
                {

                    item = mnuMerge;
                }
            }         
        }
}
2

There are 2 answers

1
AronVanAmmers On BEST ANSWER

Although this question is downvoted for good reasons, it's the only hit I got while googling for "xLayoutRow ArgumentOutOfRangeException", so I'll still share my experiences here.

I encountered an exception with the top part of the stack trace in this post:

System.ArgumentOutOfRangeException - Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
at System.Collections.ArrayList.get_Item(Int32 index)
at System.Windows.Forms.Layout.ArrangedElementCollection.get_Item(Int32 index)
at System.Windows.Forms.Layout.FlowLayout.xLayoutRow(ContainerProxy containerProxy, ElementProxy elementProxy, Int32 startIndex, Int32 endIndex, Rectangle rowBounds, Int32& breakIndex, Boolean measureOnly)
at System.Windows.Forms.Layout.FlowLayout.xLayout(IArrangedElement container, Rectangle displayRect, Boolean measureOnly)
at System.Windows.Forms.Layout.FlowLayout.GetPreferredSize(IArrangedElement container, Size proposedConstraints)

In my case the cause was, summarized:

  • A UserControl of type MyControl contains a FlowLayoutPanel.
  • Instance a of MyControl is instantiated and added to the Controls collection of a container control b: b.Controls.Add(a)
  • During this Add operation, through events triggering other events, all controls in b.Controls are disposed, including a.
  • The exception followed from the call b.Controls.Add(a) which was still unfinished.

Of course disposing the control while adding it to the controls collection was not my intention and finding the cause allowed me to solve the problem immediately. What seemed to happen was that the FlowLayoutPanel tries to do its layout, but it and its controls are being removed and disposed in-flight, which understandably makes it fail.

Maybe this helps the OP or someone else who encounters this exception.

0
rene On

The exception text of argument out of range states the following:

Index was out of range. Must be non-negative and less than the size of the collection.

And you claim this the exception occurs in this line:

mnuRoot.Items.Insert(mnuRoot.Items.IndexOf(mnuAddAfter), item);

From the stack trace we learn that the exception is thrown at the Item accessor of an Arraylist. This means that our first parameter provided in the Insert method must be either negative or larger than the size of the Arraylist. Let us first anaylize if our index value is to big.

The index is obtained from a collection of items owned by mnuRoot and also Insert in the same collection of mnuRoot. The value being to large is highly unlikey because the code is referencing the same collection. The only situation where this might go wrong is if multiple threads are updatimg that Arraylist and by judging the lock statement you try to prevent that.

Leaves the negative number as option. It appears if the reference to mnuAddAfter is not in the collection of mnuRoot.Items. As you are already checking for null I assume this is a situation that can occur.

Based on the provided codesnippet I assume you want to add item to the mnuRoot.Items collection whatever it takes

The IndexOf implementation of the ArrayList doesn't break if you search for null values, if it doesn't find1 one in the list the method returns -1. Using this knowledge the following implementation will prevent the argument out of range exception.

var index = mnuRoot.Items.IndexOf(mnuAddAfter); // if mnuAddAfter is null -1 is returned
if (index == -1)
{             
   mnuRoot.Items.Add(item);
}
else
{
    mnuRoot.Items.Insert(index, item);
}

1. for nitpickers: the ToolStripItemCollection guarantees that no null values are inserted in its collection