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

ListBox自定义不同颜色项时遇数据源绑定异常的技术问询

问题原因

异常System.ArgumentException: 'Items collection cannot be modified when the DataSource property is set.'的核心原因是:当ListBox通过DataSource绑定了数据源后,其Items集合会被锁定为只读状态,无法直接通过Items.Add/Items.Remove等方法修改。

你的代码中,在构造函数的逻辑里,当selectedPath存在且rectangles.txt文件存在时,执行了listBox1.DataSource = FileList.Keys.ToList();,这就绑定了数据源。之后再调用listBox1.Items.Add自然会触发异常。

另外,当前代码还存在一个隐藏问题:你绑定的数据源是string类型的FileList键,但要添加的是MyListBoxItem类型的对象,两者类型不统一,会导致DrawItem事件中的类型转换失败(非MyListBoxItem的项会进入else分支)。

解决方案

要同时显示FileList的键和自定义的彩色提示项,需要统一数据源类型,通过修改绑定的数据源来添加项,而不是直接操作Items集合。具体步骤如下:

1. 创建统一的列表项基类

定义一个基类来统一两种类型的列表项,确保它们都包含显示文本和颜色属性:

public class ListBoxItemBase
{
    public virtual string DisplayText { get; }
    public virtual Color ItemColor { get; } = Color.Black; // 默认黑色
}

2. 适配现有项类型

  • 修改MyListBoxItem继承自基类:
public class MyListBoxItem : ListBoxItemBase
{
    public MyListBoxItem(Color c, string m)
    {
        ItemColor = c;
        DisplayText = m;
    }
    public override Color ItemColor { get; }
    public override string DisplayText { get; }
}
  • 创建适配FileList键的子类:
public class FileKeyListItem : ListBoxItemBase
{
    private readonly string _key;
    public FileKeyListItem(string key) => _key = key;
    public override string DisplayText => _key;
}

3. 修改构造函数中的数据源绑定逻辑

不再直接绑定FileList.Keys,而是创建一个包含所有项的统一列表,再绑定到DataSource:

public Form1()
{
    InitializeComponent();

    // 保留原有初始化代码...

    List<ListBoxItemBase> listItems = new List<ListBoxItemBase>();

    if (selectedPath != "" && selectedPath != null)
    {
        if (System.IO.File.Exists(Path.Combine(selectedPath, "rectangles.txt")))
        {
            string g = System.IO.File.ReadAllText(Path.Combine(selectedPath, "rectangles.txt"));
            g = g.Remove(0, 32);
            
            FileList = JsonConvert.DeserializeObject<Dictionary<string, string>>(g);
            // 将FileList的键转换为FileKeyListItem添加到统一列表
            foreach (var key in FileList.Keys)
            {
                listItems.Add(new FileKeyListItem(key));
            }
            label2.Text = listItems.Count.ToString();
        }
        else
        {
            label2.Text = "0";
        }
    }
    else
    {
        label2.Text = "0";
    }

    // 添加自定义测试项到统一列表
    listItems.Add(new MyListBoxItem(Color.Green, "Validated data successfully"));
    listItems.Add(new MyListBoxItem(Color.Red, "Failed to validate data"));

    // 绑定统一列表作为数据源
    listBox1.DataSource = listItems;
    // 设置选中最后一项(如果有项的话)
    if (listItems.Count > 0)
    {
        listBox1.SelectedIndex = listItems.Count - 1;
    }

    // 保留原有剩余代码...
}

4. 更新DrawItem事件处理

适配统一的基类,确保所有项都能正确绘制:

private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
{
    // 绘制背景和焦点矩形(必须添加,否则选中状态显示异常)
    e.DrawBackground();
    e.DrawFocusRectangle();

    ListBoxItemBase item = listBox1.Items[e.Index] as ListBoxItemBase;
    if (item != null)
    {
        e.Graphics.DrawString(
            item.DisplayText,
            listBox1.Font,
            new SolidBrush(item.ItemColor),
            e.Bounds.X,
            e.Bounds.Y
        );
    }
    else
    {
        // 处理意外类型的项,使用默认样式绘制
        e.Graphics.DrawString(
            listBox1.Items[e.Index].ToString(),
            listBox1.Font,
            new SolidBrush(e.ForeColor),
            e.Bounds.X,
            e.Bounds.Y
        );
    }
}

5. 更新SelectedIndexChanged事件

适配新的项类型,确保FileList的项被选中时能正确加载图片:

private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    var fileItem = listBox1.SelectedItem as FileKeyListItem;
    if (fileItem != null && FileList.TryGetValue(fileItem.DisplayText, out string val))
    {
        if (File.Exists(val))
        {
            pictureBox1.Image = System.Drawing.Image.FromFile(val);
        }
    }
    // 自定义提示项被选中时可根据需求添加逻辑
}

6. 更新pictureBox2_MouseUp中的数据源更新

当新增裁剪区域后,需要重新构建统一列表并绑定:

private void pictureBox2_MouseUp(object sender, MouseEventArgs e)
{
    // 保留原有逻辑...

    if (dr.Rect.Width > 0 && dr.Rect.Height > 0)
    {
        // 保留原有保存逻辑...

        // 重新构建统一列表
        List<ListBoxItemBase> updatedItems = new List<ListBoxItemBase>();
        foreach (var key in FileList.Keys)
        {
            updatedItems.Add(new FileKeyListItem(key));
        }
        // 如果需要保留自定义提示项,可再次添加
        // updatedItems.Add(new MyListBoxItem(Color.Green, "Validated data successfully"));
        // updatedItems.Add(new MyListBoxItem(Color.Red, "Failed to validate data"));

        listBox1.DataSource = updatedItems;
        if (updatedItems.Count > 0)
        {
            listBox1.SelectedIndex = updatedItems.Count - 1;
        }

        // 保留原有剩余逻辑...
    }

    // 保留原有剩余逻辑...
}

内容的提问来源于stack exchange,提问作者Daniel Lip

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 07:31:07