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

DataGridViewComboBoxColumn二次点击触发System.NullReferenceException问题

DataGridViewComboBoxColumn二次点击触发NullReferenceException问题

我开发了一个Windows Form应用,主窗体里的DataGridView连接SQL Server数据库,其中一列是ComboBoxColumn。我通过EditingControlShowing事件把它转换成实际的ComboBox并绑定了多个事件:

private void dgrv1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
   var cb = e.Control as DataGridViewComboBoxEditingControl;
   cb.SelectedIndexChanged -= this.cb_SelectedIndexChanged;
   cb.SelectedIndexChanged += this.cb_SelectedIndexChanged;
   cb.DropDown -= this.cb_DropDown;
   cb.DropDown += this.cb_DropDown;
   cb.DropDownClosed -= this.cb_DropDownClosed;
   cb.DropDownClosed += this.cb_DropDownClosed;
}

private void cb_DropDown (object sender, EventArgs e)
{ 
    var cb = sender as DataGridViewComboBoxEditingControl;
    string text = cb.Text; 
}

private void cb_SelectedIndexChanged(object sender, EventArgs e)
{ 
    var cb = sender as DataGridViewComboBoxEditingControl;
    int ind = cb.SelectedIndex; 
    dgrv1.CommitEdit(DataGridViewDataErrorContexts.Commit);
    dgrv1.EndEdit; // 语法错误:缺少方法调用括号
}

private void cb_DropDownClosed(object sender, EventArgs e)
{ 
    var cb = sender as DataGridViewComboBoxEditingControl;
    dgrv1.EndEdit; // 语法错误:缺少方法调用括号
}

首次点击该ComboBoxColumn时所有事件正常运行,但第二次点击时,无论是否修改选中项,都会在Program.cs的Application.Run行抛出System.NullReferenceException。禁用EditingControlShowing事件则不会出现此异常。异常堆栈信息如下:

System.NullReferenceException
 at System.Windows.Forms.DataGridView.InitializeEditingControlValue(DataGridViewCellStyle& dataGridViewCellStyle, DataGridViewCell dataGridViewCell)
 at System.Windows.Forms.DataGridView.BeginEditInternal(Boolean selectAll)
 at System.Windows.Forms.DataGridView.BeginEdit(Boolean selectAll)
 at System.Windows.Forms.DataGridViewComboBoxCell.OnMouseClick(DataGridViewCellMouseEventArgs e)
 at System.Windows.Forms.DataGridView.OnMouseClick(DataGridViewCellMouseEventArgs e)
 at System.Windows.Forms.DataGridView.OnMouseClick(MouseEventArgs e)
 at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
 at System.Windows.Forms.Control.WndProc(Message& m)
 at System.Windows.Forms.DataGridView.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.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
 at System.Windows.Forms.UnsafeNativeMethods.DispatchMessage(MSG& msg)
 at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
 at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
 at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
 at System.Windows.Forms.Application.Run(Form mainForm)
 at MyProject.Program.Main() in <解决方案路径>\MyProject\Program.cs:line19

问题根源

  1. 事件管理不当:DataGridView的编辑控件是复用的,仅在EditingControlShowing中绑定事件但未在编辑结束后解绑,导致旧事件处理程序关联到已失效的控件实例,重复触发时引发空引用。
  2. 编辑流程被强制中断:在SelectedIndexChanged和DropDownClosed中提前调用EndEdit,干扰了DataGridView的内部编辑生命周期,第二次进入编辑时控件初始化失败。
  3. 语法错误:dgrv1.EndEdit缺少方法调用括号,属于编译错误,会引发意外运行时行为。
  4. 空值判断缺失:控件转换时未做空值校验,一旦转换失败直接访问属性会触发空引用异常。

修复方案

1. 完整管理事件绑定与解绑

在EditingControlShowing中绑定事件,同时在CellEndEdit事件中解绑,避免复用控件残留旧引用:

private void dgrv1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
    var cb = e.Control as DataGridViewComboBoxEditingControl;
    if (cb == null) return; // 增加空值判断

    // 先解绑再绑定,防止重复绑定
    cb.SelectedIndexChanged -= cb_SelectedIndexChanged;
    cb.SelectedIndexChanged += cb_SelectedIndexChanged;
    cb.DropDown -= cb_DropDown;
    cb.DropDown += cb_DropDown;
    cb.DropDownClosed -= cb_DropDownClosed;
    cb.DropDownClosed += cb_DropDownClosed;
}

private void dgrv1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
    var cb = dgrv1.EditingControl as DataGridViewComboBoxEditingControl;
    if (cb == null) return;

    // 编辑结束后解绑事件
    cb.SelectedIndexChanged -= cb_SelectedIndexChanged;
    cb.DropDown -= cb_DropDown;
    cb.DropDownClosed -= cb_DropDownClosed;
}

2. 调整编辑提交逻辑

移除SelectedIndexChanged和DropDownClosed中的强制EndEdit调用,改用CellValueChanged处理值变更后的业务逻辑:

private void dgrv1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
    // 仅处理ComboBox列的变更
    if (dgrv1.Columns[e.ColumnIndex] is DataGridViewComboBoxColumn)
    {
        var selectedValue = dgrv1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
        // 这里添加值变更后的处理逻辑
    }
}

// 修改原SelectedIndexChanged方法,仅保留必要逻辑
private void cb_SelectedIndexChanged(object sender, EventArgs e)
{
    var cb = sender as DataGridViewComboBoxEditingControl;
    if (cb == null) return;
    int ind = cb.SelectedIndex;
    // 不要在此处调用EndEdit/CommitEdit
}

3. 修复语法错误

确保所有方法调用带有括号:

// 修正后的代码示例
dgrv1.EndEdit();
dgrv1.CommitEdit(DataGridViewDataErrorContexts.Commit);

4. 全局增加空值判断

所有涉及控件转换的方法都添加空值校验:

private void cb_DropDown(object sender, EventArgs e)
{
    var cb = sender as DataGridViewComboBoxEditingControl;
    if (cb == null) return;
    string text = cb.Text;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 12:15:17