You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
        }
    }
}

问题根源分析

  1. 数据源不匹配:listBox1绑定的是FileList.Keys.ToList(),但事件中却访问MyItems列表,两者元素数量可能不一致,导致SelectedIndex对应不上MyItems的索引范围。
  2. 无边界校验:SelectedIndexChanged事件中直接使用SelectedIndex,未判断该值是否在MyItems的有效索引范围内(0 ≤ index < MyItems.Count)。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 01:58:17