如何在自定义DataGridView控件中访问窗体的DataGridView引用?
问题描述
我想在自定义的smartdatagridview控件中,从Form1.cs类传入并访问仅在Form1.cs中使用的dataGridView1的引用。原因是我的Windows应用的每个窗体中都会有一个新的DataGridView(名称均不同),这些控件的引用需要被该自定义DataGridView用于特定用途。请问是否可以实现?如果不行,有什么替代方案?
现有代码
public partial class smartdatagridview : DataGridView { public smartdatagridview() { InitializeComponent(); } private TextBox textBox; protected override void OnEnter(EventArgs e) { base.OnEnter(e); CurrentCell = this[0, 0]; BeginEdit(true); } protected override void OnEditingControlShowing(DataGridViewEditingControlShowingEventArgs e) { base.OnEditingControlShowing(e); if (CurrentCell.ColumnIndex == 0 && e.Control is TextBox) { textBox = (TextBox)e.Control; textBox.TextChanged -= Text_Changed; textBox.KeyDown -= Key_down; textBox.Enter -= Key_Enter; textBox.TextChanged += Text_Changed; textBox.KeyDown += Key_down; textBox.Enter +=Key_Enter; } else { textBox = null; } } protected override void OnCellEndEdit(DataGridViewCellEventArgs e) { base.OnCellEndEdit(e); if (textBox != null) { textBox.TextChanged -= Text_Changed; textBox.KeyDown -= Key_down; textBox.Enter -= Key_Enter; textBox = null; } if (this.CurrentCell.ColumnIndex == 0) { if (dataGridView1.Rows.Count > 0) // 报错:找不到dataGridView1 { this.CurrentCell.Value = dataGridView1.SelectedRows[0].Cells[1].Value.ToString(); // 报错 dataGridView1.Visible = false; // 报错 } } } }
解决方案
完全可以实现,推荐两种实用方案:
方案一:给自定义控件加公共属性传引用
在smartdatagridview类里新增一个公共属性,用来接收外部传入的目标DataGridView:
public partial class smartdatagridview : DataGridView { // 新增属性,用来存外部传入的DataGridView引用 public DataGridView TargetDataGridView { get; set; } public smartdatagridview() { InitializeComponent(); } // 原有代码保持不变... protected override void OnCellEndEdit(DataGridViewCellEventArgs e) { base.OnCellEndEdit(e); if (textBox != null) { textBox.TextChanged -= Text_Changed; textBox.KeyDown -= Key_down; textBox.Enter -= Key_Enter; textBox = null; } if (this.CurrentCell.ColumnIndex == 0) { // 替换原来的dataGridView1为TargetDataGridView,先判空防报错 if (TargetDataGridView != null && TargetDataGridView.Rows.Count > 0) { this.CurrentCell.Value = TargetDataGridView.SelectedRows[0].Cells[1].Value.ToString(); TargetDataGridView.Visible = false; } } } }
然后在窗体(比如Form1.cs)里,初始化自定义控件时把目标DataGridView传进去:
// 假设你的自定义控件实例叫smartDataGridView1 smartDataGridView1.TargetDataGridView = dataGridView1;
方案二:用事件通知窗体执行操作(解耦更彻底)
如果不想让自定义控件直接依赖外部的DataGridView,用事件触发窗体自己处理逻辑更合理:
- 先在自定义控件里定义事件和参数类:
public partial class smartdatagridview : DataGridView { // 定义事件,用来通知窗体需要执行相关操作 public event EventHandler<CellEndEditOperationArgs> OnNeedTargetGridOperation; // 自定义事件参数,用来传递当前单元格等需要的数据 public class CellEndEditOperationArgs : EventArgs { public DataGridViewCell CurrentCell { get; set; } } public smartdatagridview() { InitializeComponent(); } // 原有代码保持不变... protected override void OnCellEndEdit(DataGridViewCellEventArgs e) { base.OnCellEndEdit(e); if (textBox != null) { textBox.TextChanged -= Text_Changed; textBox.KeyDown -= Key_down; textBox.Enter -= Key_Enter; textBox = null; } if (this.CurrentCell.ColumnIndex == 0) { // 触发事件,把当前单元格传递给窗体 OnNeedTargetGridOperation?.Invoke(this, new CellEndEditOperationArgs { CurrentCell = this.CurrentCell }); } } }
- 在窗体(Form1.cs)里订阅这个事件,处理具体逻辑:
public Form1() { InitializeComponent(); // 订阅自定义控件的事件 smartDataGridView1.OnNeedTargetGridOperation += SmartDataGridView1_OnNeedTargetGridOperation; } private void SmartDataGridView1_OnNeedTargetGridOperation(object sender, smartdatagridview.CellEndEditOperationArgs e) { if (dataGridView1.Rows.Count > 0) { e.CurrentCell.Value = dataGridView1.SelectedRows[0].Cells[1].Value.ToString(); dataGridView1.Visible = false; } }
方案选择建议
- 方案一:实现简单直接,适合逻辑简单的小场景;
- 方案二:遵循面向对象的解耦原则,自定义控件不用关心外部控件的细节,只负责触发事件,更适合复杂项目或需要复用自定义控件的场景。
内容的提问来源于stack exchange,提问作者ankit goel
相关产品推荐
相关产品推荐

