DataGridView的绑定表在双击时仅生成一个RowChanged事件。我该如何做两个?
我有一个DataGridView,其数据源是一个数据表。
此DataTable有一个布尔列,该列被解释为DataGridView中的一个复选框。
employeeSelectionTable.Columns.Add("IsSelected", typeof(bool)); ... employeeSelectionTable.RowChanged += selectionTableRowChanged; dataGridViewSelectedEmployees.DataSource = employeeSelectionTable; ... private void selectionTableRowChanged(object sender, DataRowChangeEventArgs e) { if ((bool)e.Row["IsSelected"]) { Console.Writeline("Is Selected"); } else { Console.Writeline("Is Not Selected"); } break; }
当用户单击复选框时,它会被选中,并且selectionTableRowChanged将输出"已选中"。
同样,当用户再次对其进行检查时,该框将被清除,并且selectionTableRowChanged输出"未选中"。
这是我遇到的问题:
当用户双击该复选框时,该复选框被选中,RowChanged事件被调用("已选择"),然后该复选框被清除,并且没有相应的RowChanged事件被调用。现在,RowChanged事件的订阅者已不同步。
现在,我的解决方案是子类化DataGridView并重写WndProc来吃WM_LBUTTONDBLCLICK,因此,双击该控件都将被忽略。
有更好的解决方案吗?
解决方案
有什么理由需要做这么低的水平? DoubleClick方法可以只是吃掉它的空方法吗?
我已经尝试重写DataGridView子类中的OnDoubleClick方法,但是什么也没做,但是仍然允许再次更改复选框。
理想情况下,我希望让DataTable的RowChanged事件被调用两次。
有没有一种方法可以通过重写的OnDoubleClick方法来影响基础DataTable?
为什么不仅仅让IsSelected列不受限制?使用CellContentClick事件将数据推送到基础数据表,而将CellDoubleClick或者RowChange事件保留为空。
private void dgv_CellContentClick(object sender, DataGridViewCellEventArgs e) { if(e.ColumnIndex == <columnIndex of IsSelected>) { string value = dgv[e.ColumnIndex, e.RowIndex].EditedFormattedValue; if( value == null || Convert.ToBoolean(value) == false) { //push false to employeeSelectionTable } else { //push true to employeeSelectionTable } } }
制作空DoubleClick事件方法无济于事的原因是,除了双击时发生的其他操作外,还执行了该方法。
如果查看Windows生成的代码或者以编程方式添加事件处理程序的示例,请使用+ =分配事件处理程序。这意味着,除了已经存在的事件处理程序之外,还要添加该事件处理程序,我们可能会在save事件上触发多个事件处理程序。
我的本能是重写DataGridView类,然后重写OnDoubleClick方法,而不调用基本的OnDoubleClick方法。
但是,我已经对此进行了快速测试,并看到了一些有趣的结果。
我整理了以下测试类:
using System; using System.Windows.Forms; namespace TestApp { class DGV : DataGridView { private string test = ""; protected override void OnDoubleClick(EventArgs e) { MessageBox.Show(test + "OnDoubleClick"); } protected override void OnCellMouseDoubleClick(System.Windows.Forms.DataGridViewCellMouseEventArgs e) { MessageBox.Show(test + "OnCellMouseDoubleClick"); } protected override void OnCellMouseClick(System.Windows.Forms.DataGridViewCellMouseEventArgs e) { if (e.Clicks == 1) { // Had to do this with a variable as using a MessageBox // here would block us from pulling off a double click test = "1 click "; base.OnCellMouseClick(e); } else { MessageBox.Show("OnCellMouseClick"); } } } }
然后将其插入Windows窗体,添加一个复选框列并运行该程序。
在全新运行中,双击复选框会使消息框显示为" 1单击OnDoubleClick"。
这意味着OnCellMouseClick在双击的第一部分执行,然后OnDoubleClick在第二次单击执行。
同样,不幸的是,删除对基本方法的调用似乎并没有阻止复选框将点击传递给它。
我怀疑要使此方法起作用,可能必须进一步采取措施,并忽略忽略双击的DataGridViewCheckBoxColumn和DataGridViewCheckBoxCell。假设此方法有效,我们将能够停止双击该复选框,但仍将其保留在其他列控件上。
我在这里发布了另一个问题的答案,该问题讨论有关创建自定义DataGridView列和单元格的问题。
不知道为什么要这样做,但是我能够在datagridview刷新中添加一个计时器滴答事件,该事件在第二次单击后便刷新了dgv。
单元格内点击事件
** _RefreshTimer = new Timer(); _RefreshTimer.Tick += new EventHandler(RefreshTimer_Tick); _RefreshTimer.Interval = 100; _RefreshTimer.Start(); } } } void RefreshTimer_Tick(object sender, EventArgs e) { dgv.Refresh(); _RefreshTimer.Stop(); _RefreshTimer = null; }**
如果我们想在DataGridView内创建一个复选框列,请创建如下所示的内容:
DataGridViewCheckBoxCell checkBoxCell = new MyDataGridViewCheckBoxCell(); ... DataGridViewColumn col = new DataGridViewColumn(checkBoxCell); ... col.Name = "colCheckBox"; ... this.dgItems.Columns.Add(col);
其中dgItems是DataGridView实例。
如我们所见,我有一个MyDataGridViewCheckBoxCell类,它是DataGridViewCheckBoxCell类的子类。在此子类中,我定义:
protected override void OnContentDoubleClick(DataGridViewCellEventArgs e) { //This the trick to keep the checkbox in sync with other actions. //base.OnContentDoubleClick(e); }
当用户现在双击复选框列中的复选框时,该复选框的行为就像单击一样。这应该可以解决同步问题。
这不是一个完美的解决方案,但是为什么不简单地执行以下操作呢?
private void dgv_CellDoubleClick(object sender, DataGridViewCellEventArgs e) { dgv_CellClick(sender, e); }
这将显式强制第二个CellClick事件,并避免不同步。