I'm getting the following unhandled exception in a specific case and I can't seem to work out why or stop it:
System.ArgumentOutOfRangeException: InvalidArgument=Value of '0' is not valid for 'index'.
Parameter name: index
at System.Windows.Forms.ComboBox.ObjectCollection.get_Item(Int32 index)
at System.Windows.Forms.ComboBox.get_SelectedItem()
at System.Windows.Forms.ComboBox.get_Text()
at System.Windows.Forms.ComboBox.WmReflectCommand(Message& m)
at System.Windows.Forms.ComboBox.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
The ComboBox in question is a list of mounted drives and when the drive list is refreshed the list is cleared and re-populated.
If the software loads with 0 drives attached, clicking the ComboBox doesn't produce the above error.
If the software loads with 1 or more drives attached and they are removed without clicking on the ComboBox during the refresh, clicking on the ComboBox afterwards doesn't produce the error.
If the software has 1 or more drives attached and the ComboBox's drop down list is currently shown and all of the drives are removed, then the list empties, but clicking on the empty box does produce the above error. Continuing and clicking again causes the error again.
When a drive is attached/detached the following code on the form containing the ComboBox is called:
this.cbxDrives.Items.Clear();
foreach (Drive phone in phones)
this.cbxDrives.Items.Add(phone);
if (this.cbxDrives.Items.Count > 1) {
this.cbxDrives.Items.Add(SynchronisedDrive.Instance);
this.cbxDrives.SelectedIndex = 0;
} else if(this.cbxDrives.Items.Count == 1)
this.cbxDrives.SelectedIndex = 0;
else
this.DriveView.Clear();
this.cbxDrives.DisplayMember = "Name";
Also, I don't know if this is relevant since the exception only mentions the base class, but the ComboBox is overridden to provide an Icon next to the text. The code for this is as follows:
protected override void OnDrawItem(DrawItemEventArgs e)
{
if (e.Index >= 0 && e.Index < Items.Count)
{
e.DrawBackground();
e.DrawFocusRectangle();
Drive item;
Rectangle bounds = e.Bounds;
int offset = 0;
item = (Drive)Items[e.Index];
if (item is SynchronisedDrive)
{
imageList.Draw(e.Graphics, bounds.Left, bounds.Top, (int)IconIndexes.ALL);
offset = imageList.ImageSize.Width;
} else {
if (item.Settings.Type == Settings.DriveTypeEnum.Headset)
{
if (item.Settings.Description.StartsWith("A R"))
{
imageList.Draw(e.Graphics, bounds.Left, bounds.Top, (int)IconIndexes.RED);
offset = imageList.ImageSize.Width;
}
else if (item.Settings.Description.StartsWith("A B"))
{
imageList.Draw(e.Graphics, bounds.Left, bounds.Top, (int)IconIndexes.BLUE);
offset = imageList.ImageSize.Width;
}
else if (item.Settings.Description.StartsWith("A G"))
{
imageList.Draw(e.Graphics, bounds.Left, bounds.Top, (int)IconIndexes.GREEN);
offset = imageList.ImageSize.Width;
}
else if (item.Settings.Description.StartsWith("A P"))
{
imageList.Draw(e.Graphics, bounds.Left, bounds.Top, (int)IconIndexes.PURPLE);
offset = imageList.ImageSize.Width;
}
else if (item.Settings.Description.StartsWith("An"))
{
imageList.Draw(e.Graphics, bounds.Left, bounds.Top, (int)IconIndexes.ORANGE);
offset = imageList.ImageSize.Width;
}
else if (item.Settings.Description.StartsWith("A Y"))
{
imageList.Draw(e.Graphics, bounds.Left, bounds.Top, (int)IconIndexes.YELLOW);
offset = imageList.ImageSize.Width;
}
}
else if (item.Settings.Type == Settings.DriveTypeEnum.RemoteConsole)
{
imageList.Draw(e.Graphics, bounds.Left, bounds.Top, (int)IconIndexes.REMOTE);
offset = imageList.ImageSize.Width;
}
else if (item.Settings.Type == Settings.DriveTypeEnum.LL)
{
imageList.Draw(e.Graphics, bounds.Left, bounds.Top, (int)IconIndexes.LL);
offset = imageList.ImageSize.Width;
}
}
e.Graphics.DrawString(item.Name, e.Font, new
SolidBrush(e.ForeColor), bounds.Left + offset, bounds.Top);
}
base.OnDrawItem(e);
}
Is there some cross threading going on here?
I mean.. how I the list refreshed. Is there are drives that show on the list, they should be Attached as you say, and if they're not on the list then it shouldn't be accessible?
Two options:
Since the list is updated async. A proper solution would be make sure the combo box is disabled before your asynchronous method updates it. Once updated, it should then enable it again.
Why not disable the combo box when all your drives are detached?
You might also want to make sure your asynchronous method is not randomly appending items one-by-one on the fly. I could see that as a problem is the user drops down the combo box while its being updated. You probably want to Disable the Combo Box >> Then Clear all your Drives and add them into the list.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With