C# WinForms列表索引越界问题:SelectedIndex与元素数量相等
列表索引越界异常排查与解决
问题核心
触发IndexOutOfRangeException,原因是listBox1.SelectedIndex的值等于MyItems的元素总数。例如SelectedIndex=6时,MyItems仅含6个元素(有效索引范围0-5),直接访问会越界;尝试用SelectedIndex-1又会在SelectedIndex=0时触发异常。
异常出现在listBox1_SelectedIndexChanged事件的这一行:
var si = tt[listBox1.SelectedIndex].Message;
触发流程:在PictureBox绘制矩形后松开鼠标,触发pictureBox2_MouseUp事件,该事件中重新绑定ListBox数据源并设置选中项,进而触发SelectedIndexChanged事件,此时出现索引不匹配问题。
相关代码片段
1. 全局变量定义
BindingList<MyListBoxItem> MyItems { get; } = new BindingList<MyListBoxItem>();
2. MyListBoxItem类定义
public class MyListBoxItem { public Color ItemColor { get; set; } public string Message { get; set; } }
3. SelectedIndexChanged事件处理
private void listBox1_SelectedIndexChanged(object sender, EventArgs e) { var tt = MyItems.ToList(); var si = tt[listBox1.SelectedIndex].Message; var val = si; int index = val.LastIndexOf(","); string you = val.Substring(index + 1); if (File.Exists(you)) { pictureBox1.Image = System.Drawing.Image.FromFile(you); } }
4. MouseUp事件触发代码
int count = 0; private void pictureBox2_MouseUp(object sender, MouseEventArgs e) { if (e.Button != MouseButtons.Left || crop == false) return; if (DrawingRects.Count > 0 && pictureBox2.Image != null && selectedPath != "") { if ((x >= 0 && x <= pictureBox2.Image.Size.Width) && (y >= 0 && y <= pictureBox2.Image.Size.Height)) { var dr = DrawingRects.Last(); if (dr.Rect.Width > 0 && dr.Rect.Height > 0) { rectImage = cropAtRect((Bitmap)pictureBox2.Image, dr.Rect); if (saveRectangles) { count++; rectangleName = GetNextName(Path.Combine(selectedPath, "Rectangle"), ".bmp"); FileList.Add($"{dr.Location}, {dr.Size}", rectangleName); string json = JsonConvert.SerializeObject( FileList, Formatting.Indented ); using (StreamWriter sw = new StreamWriter(Path.Combine(selectedPath, "rectangles.txt"), false)) { sw.WriteLine("Total number of rectangles: " + count + Environment.NewLine); sw.Write(json); sw.Close(); } rectImage.Save(rectangleName); saveRectanglesCounter++; } else { var stream = ToMemoryStream(rectImage); var image = System.Drawing.Image.FromStream(stream); pictureBox1.Image = image; } pixelsCounter = rect.Width * rect.Height; pictureBox1.Invalidate(); listBox1.DataSource = FileList.Keys.ToList(); listBox1.SelectedIndex = listBox1.Items.Count - 1; pictureBox2.Focus(); Graphics g = Graphics.FromImage(this.pictureBox1.Image); g.Clear(this.pictureBox1.BackColor); } } else { if (clearRectangles) { DrawingRects.Clear(); pictureBox2.Invalidate(); } x = 0; y = 0; } } }
问题根源分析
- 数据源不匹配:
listBox1绑定的是FileList.Keys.ToList(),但事件中却访问MyItems列表,两者元素数量可能不一致,导致SelectedIndex对应不上MyItems的索引范围。 - 无边界校验:
SelectedIndexChanged事件中直接使用SelectedIndex,未判断该值是否在MyItems的有效索引范围内(0 ≤ index < MyItems.Count)。 - MouseUp事件潜在问题:设置
listBox1.SelectedIndex = listBox1.Items.Count - 1时,若Items.Count为0,会导致SelectedIndex=-1,后续访问也会出错。
解决方案
方案1:统一数据源(从根源避免不匹配)
如果listBox1应该绑定MyItems,修改MouseUp事件中的数据源绑定代码:
// 替换原来的listBox1.DataSource = FileList.Keys.ToList(); listBox1.DataSource = MyItems; // 同时确保MyItems的Message数据与FileList同步
方案2:添加严格边界校验(推荐,兼容异常场景)
修改SelectedIndexChanged事件,先校验索引有效性:
private void listBox1_SelectedIndexChanged(object sender, EventArgs e) { var tt = MyItems.ToList(); // 校验索引是否在有效范围内 if (listBox1.SelectedIndex < 0 || listBox1.SelectedIndex >= tt.Count) { pictureBox1.Image = null; // 可选:清空图片 return; } var si = tt[listBox1.SelectedIndex].Message; var val = si; int index = val.LastIndexOf(","); // 额外校验:确保找到逗号,避免Substring越界 if (index == -1) { return; } string you = val.Substring(index + 1); if (File.Exists(you)) { pictureBox1.Image = System.Drawing.Image.FromFile(you); } }
方案3:修复MouseUp事件的索引设置
在MouseUp事件中设置选中项前,先判断Items数量:
// 替换原来的listBox1.SelectedIndex = listBox1.Items.Count - 1; if (listBox1.Items.Count > 0) { listBox1.SelectedIndex = listBox1.Items.Count - 1; } else { listBox1.SelectedIndex = -1; // 无项时取消选中 }
额外建议
- 确保
MyItems和listBox1的数据源始终同步,避免数据不一致。 - 对
Image.FromFile等操作添加异常捕获,处理文件损坏、权限不足等情况,增强程序稳定性。
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

