WinForms多窗体调用Change()触发NullReferenceException问题排查
WinForms多窗体修改数据空引用异常解决方法
问题核心原因
子窗体点击Change按钮时,创建了全新的MainForm实例,这个新实例的dataGridView1既没有加载数据库数据,也没有选中行,导致dataGridView1.CurrentCell为null,触发空引用异常。同时主窗体的Change()方法里还新建了Full_Inf_Form实例,根本拿不到当前打开的子窗体中修改后的数据。
具体解决方案
1. 子窗体持有主窗体的真实引用
修改子窗体代码,添加接收主窗体实例的构造函数,保存主窗体引用:
// 子窗体类内添加私有字段保存主窗体引用 private MainForm _mainForm; // 重写子窗体构造函数,接收主窗体实例 public Full_Inf_Form(MainForm mainForm) { InitializeComponent(); _mainForm = mainForm; } // 修改Change按钮点击事件 private void buttonChange2_Click(object sender, EventArgs e) { // 调用已有主窗体的Change方法,传递当前子窗体实例 _mainForm.Change(this); }
2. 主窗体打开子窗体时传递自身实例
修改主窗体打开子窗体的代码,传入当前主窗体实例:
// 确保selectedRow是主窗体的类级别字段 private int selectedRow = -1; private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e) { selectedRow = e.RowIndex; if (e.RowIndex >= 0) { // 传入当前主窗体实例创建子窗体 Full_Inf_Form fullInfForm = new Full_Inf_Form(this); DataGridViewRow row = dataGridView1.Rows[selectedRow]; fullInfForm.textBoxID_Inf.Text = row.Cells[0].Value.ToString(); fullInfForm.textBoxStNa_Inf.Text = row.Cells[1].Value.ToString(); fullInfForm.textBoxLaNa_Inf.Text = row.Cells[2].Value.ToString(); fullInfForm.textBoxStPa_Inf.Text = row.Cells[3].Value.ToString(); fullInfForm.textBoxNumb_Inf.Text = row.Cells[4].Value.ToString(); fullInfForm.textBoxEmail_Inf.Text = row.Cells[5].Value.ToString(); fullInfForm.textBoxGrup_Inf.Text = row.Cells[6].Value.ToString(); fullInfForm.textBoxSpec_Inf.Text = row.Cells[7].Value.ToString(); fullInfForm.textBoxDataVst_Inf.Text = row.Cells[8].Value.ToString(); fullInfForm.textBoxStSt_Inf.Text = row.Cells[9].Value.ToString(); fullInfForm.textBoxBalMat_Inf.Text = row.Cells[10].Value.ToString(); fullInfForm.textBoxBalUkr_Inf.Text = row.Cells[11].Value.ToString(); fullInfForm.textBoxBalEng_Inf.Text = row.Cells[12].Value.ToString(); fullInfForm.Show(); } }
3. 修改主窗体Change方法,接收子窗体数据
调整主窗体Change()方法,直接从传入的子窗体实例获取修改后的数据,并用已保存的选中行索引操作:
// 修改Change方法,接收子窗体实例 public void Change(Full_Inf_Form currentSubForm) { // 校验选中行索引有效性 if (selectedRow < 0 || selectedRow >= dataGridView1.Rows.Count) return; // 从传入的子窗体获取修改后的数据 var id = currentSubForm.textBoxID_Inf.Text; var name = currentSubForm.textBoxStNa_Inf.Text; var lastname = currentSubForm.textBoxLaNa_Inf.Text; var patr = currentSubForm.textBoxStPa_Inf.Text; var numb = currentSubForm.textBoxNumb_Inf.Text; var email = currentSubForm.textBoxEmail_Inf.Text; var grup = currentSubForm.textBoxGrup_Inf.Text; var spec = currentSubForm.textBoxSpec_Inf.Text; var data = currentSubForm.textBoxDataVst_Inf.Text; var sypend = currentSubForm.textBoxStSt_Inf.Text; var mat = currentSubForm.textBoxBalMat_Inf.Text; var ukr = currentSubForm.textBoxBalUkr_Inf.Text; var eng = currentSubForm.textBoxBalEng_Inf.Text; var targetRow = dataGridView1.Rows[selectedRow]; // 安全校验单元格值 if (!string.IsNullOrEmpty(targetRow.Cells[0].Value?.ToString())) { targetRow.SetValues(id, name, lastname, patr, numb, email, grup, spec, data, sypend, mat, ukr, eng); targetRow.Cells[13].Value = RowState.Modified; } }
关键说明
- 核心逻辑是共享实例而非新建实例:子窗体操作的是已经加载数据的主窗体,不是空的新实例;
- 用类级别字段
selectedRow保存选中行索引,比依赖CurrentCell更可靠,避免主窗体焦点丢失导致CurrentCell为空的情况; - 通过传递子窗体实例直接获取修改后的数据,无需重新创建子窗体。
内容的提问来源于stack exchange,提问作者Oleg Losh
相关产品推荐
相关产品推荐

