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事件,并避免不同步。

