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

DataGridViewComboBoxCell联动异常:如何规避值无效ArgumentException?

问题描述

我在使用DataGridView的两个DataGridViewComboBoxCell列时遇到问题:当更改某一行中列1的选项时,希望列2对应单元格的下拉列表项随之变更。默认状态下列2无选项,执行以下操作序列会触发异常:

  • 在列1中选择“1”,触发col1Changed事件并更新列2的单元格选项;
  • 在列2中选择“item1”;
  • 尝试再次选择列1中的选项。

此时会触发如下异常:

DataGridView中发生以下异常:
System.ArgumentException: DataGridViewComboBoxCell值无效。
请处理DataError事件以替换此默认对话框。

问题代码如下:

void initaliseGrid()
{
    string[] itemsCol1 = new string[] { "1", "2", "3" };
    DataGridViewComboBoxColumn col1 = new DataGridViewComboBoxColumn();
    col1.DropDownWidth = 200;
    col1.Width = 200;
    col1.MaxDropDownItems = 3;
    col1.HeaderText = "col 1";
    col1.ReadOnly = false;
    dataGridView1.Columns.Insert(0, col1);
    col1.Items.AddRange(itemsCol1);

    DataGridViewComboBoxColumn col2 = new DataGridViewComboBoxColumn();
    col2.DropDownWidth = 200;
    col2.Width = 200;
    col2.MaxDropDownItems = 3;
    col2.HeaderText = "col 2";
    col2.ReadOnly = true;
    dataGridView1.Columns.Insert(1, col2);

}

int col1Idx = 0;
int col2Idx = 1;

private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
    // Check if the curent cell is combobox
    if (dataGridView1.CurrentCell.ColumnIndex == colqIdx && e.Control is ComboBox)
    {
        ComboBox comboBox = e.Control as ComboBox;
        // Add an event when combobox index is changed
        comboBox.SelectedIndexChanged += col1Changed;
    }
}

private void col1Changed(object sender, EventArgs e)
{
    var currentcell = dataGridView1.CurrentCellAddress;
    if (currentcell.X == col1Idx)
    {
        // Read the selected item
        string selectedItem = ((ComboBox)sender).SelectedItem.ToString();
        // Get the cellfrom column 2
        DataGridViewComboBoxCell comboBox = (DataGridViewComboBoxCell)dataGridView1.Rows[currentcell.X].Cells[col2Idx];
        if (selectedItem == "1")
        {
            comboBox.Items.Clear();
            comboBox.Items.Add("item1");
            comboBox.Items.Add("item2");
            comboBox.ReadOnly = false;
        }
        else if (selectedItem == "2")
        {
            comboBox.Items.Clear();
            comboBox.Items.Add("item3");
            comboBox.Items.Add("item4");
            comboBox.ReadOnly = false;
        }
        else
        {
            comboBox.Items.Clear();
            comboBox.ReadOnly = true;
        }
    }
}
错误原因

异常核心原因:当再次修改列1选项时,列2单元格已选中的item1不在新的下拉选项集合中(比如选列1的"2"时,列2选项变为item3、item4;选"3"时列2选项被清空)。DataGridView会校验ComboBoxCell的当前值是否存在于其Items集合中,校验不通过就抛出参数异常。

此外代码还有两处错误:

  1. dataGridView1_EditingControlShowing中的colqIdx是笔误,应为col1Idx;
  2. col1Changed中获取列2单元格时,dataGridView1.Rows[currentcell.X]错误,currentcell.X是列索引,应使用currentcell.Y(行索引)获取对应行。
解决方案

关键是更新列2的Items集合前,先清空该单元格的当前值,确保校验通过,同时修正代码中的笔误和索引错误:

修正后的完整代码

void initaliseGrid()
{
    string[] itemsCol1 = new string[] { "1", "2", "3" };
    DataGridViewComboBoxColumn col1 = new DataGridViewComboBoxColumn();
    col1.DropDownWidth = 200;
    col1.Width = 200;
    col1.MaxDropDownItems = 3;
    col1.HeaderText = "col 1";
    col1.ReadOnly = false;
    dataGridView1.Columns.Insert(0, col1);
    col1.Items.AddRange(itemsCol1);

    DataGridViewComboBoxColumn col2 = new DataGridViewComboBoxColumn();
    col2.DropDownWidth = 200;
    col2.Width = 200;
    col2.MaxDropDownItems = 3;
    col2.HeaderText = "col 2";
    col2.ReadOnly = true;
    dataGridView1.Columns.Insert(1, col2);

}

int col1Idx = 0;
int col2Idx = 1;

private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
    // 修正笔误:colqIdx改为col1Idx
    if (dataGridView1.CurrentCell.ColumnIndex == col1Idx && e.Control is ComboBox)
    {
        ComboBox comboBox = e.Control as ComboBox;
        // 先移除已绑定事件,避免重复绑定导致多次触发
        comboBox.SelectedIndexChanged -= col1Changed;
        comboBox.SelectedIndexChanged += col1Changed;
    }
}

private void col1Changed(object sender, EventArgs e)
{
    var currentcell = dataGridView1.CurrentCellAddress;
    if (currentcell.X == col1Idx)
    {
        string selectedItem = ((ComboBox)sender).SelectedItem.ToString();
        // 修正索引错误:currentcell.Y是行索引,不是currentcell.X
        DataGridViewComboBoxCell comboBoxCell = (DataGridViewComboBoxCell)dataGridView1.Rows[currentcell.Y].Cells[col2Idx];
        
        // 关键步骤:先清空列2单元格的当前值
        comboBoxCell.Value = null;
        
        comboBoxCell.Items.Clear();
        if (selectedItem == "1")
        {
            comboBoxCell.Items.Add("item1");
            comboBoxCell.Items.Add("item2");
            comboBoxCell.ReadOnly = false;
        }
        else if (selectedItem == "2")
        {
            comboBoxCell.Items.Add("item3");
            comboBoxCell.Items.Add("item4");
            comboBoxCell.ReadOnly = false;
        }
        else
        {
            comboBoxCell.ReadOnly = true;
        }
    }
}

额外优化建议

  1. 在EditingControlShowing中先移除事件再添加,避免单元格多次进入编辑状态时重复绑定SelectedIndexChanged事件,导致一次选择触发多次col1Changed;
  2. 若需保留列2的选中值(当新Items集合包含该值时),可先判断当前值是否存在于新集合,不存在再清空:
// 替换原清空Value的代码
string currentCol2Value = comboBoxCell.Value?.ToString();
comboBoxCell.Items.Clear();

// 先添加新选项
if (selectedItem == "1")
{
    comboBoxCell.Items.Add("item1");
    comboBoxCell.Items.Add("item2");
    comboBoxCell.ReadOnly = false;
}
// ...其他分支

// 检查原值是否在新集合中,存在则保留,否则清空
if (!string.IsNullOrEmpty(currentCol2Value) && comboBoxCell.Items.Contains(currentCol2Value))
{
    comboBoxCell.Value = currentCol2Value;
}
else
{
    comboBoxCell.Value = null;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 01:02:05