如何检测 DataGridView CheckBox 事件变化?
Posted
技术标签:
【中文标题】如何检测 DataGridView CheckBox 事件变化?【英文标题】:How to detect DataGridView CheckBox event change? 【发布时间】:2012-08-07 09:59:36 【问题描述】:我有一个 winforms 应用程序,并希望在选中/取消选中嵌入在 DataGridView
控件中的复选框时触发一些代码。我尝试过的每个事件
-
在单击
CheckBox
但在其选中状态更改之前触发,或
仅在 CheckBox
失去焦点时触发
我似乎找不到在选中状态更改后立即触发的事件。
编辑:
我想要实现的是,当一个DataGridView
中的CheckBox
的选中状态发生变化时,另外两个DataGridView
s 中的数据也会发生变化。然而,我使用过的所有事件,其他网格中的数据仅在第一个 DataGridView
中的 CheckBox
失去焦点后发生变化。
【问题讨论】:
你检查CurrentCellDirtyStateChanged
事件了吗?
仍然只在用户“离开”单元格时执行。
这是 MSDN 上的文章:msdn.microsoft.com/en-us/library/… 与 Killercam 的回答类似但略有不同
您可能需要考虑将ListView
与listView.View = System.Windows.Forms.View.Details; listView.CheckBoxes = true;
一起使用,然后它会显示为一个表格,开头带有复选框。在那里,您可以使用 listView.ItemCheck += new System.Windows.Forms.ItemCheckEventHandler(methodname);
轻松解决 Checkbox 选中事件
【参考方案1】:
要处理DatGridView
s CheckedChanged
事件,您必须首先触发CellContentClick
(它没有CheckBox
es 当前状态!)然后调用CommitEdit
。这将反过来触发CellValueChanged
事件,您可以使用该事件来完成您的工作。 这是 Microsoft 的疏忽。执行以下操作...
private void dataGridViewSites_CellContentClick(object sender,
DataGridViewCellEventArgs e)
dataGridViewSites.CommitEdit(DataGridViewDataErrorContexts.Commit);
/// <summary>
/// Works with the above.
/// </summary>
private void dataGridViewSites_CellValueChanged(object sender,
DataGridViewCellEventArgs e)
UpdateDataGridViewSite();
我希望这会有所帮助。
附:查看这篇文章https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged(v=vs.110).aspx
【讨论】:
这是一个很好的解决方案,但如果用户点击几次就不起作用,在***.com/questions/11843488/…下方发布了替代方案 我也强烈建议不要将此解决方案用于双击问题。需要调用EndEdit()函数……从@56ka找到链接,点击文章链接! 我并没有在这个解决方案上花费很长时间,如果@56ka 的解决方案更好,那就太好了。但是,我不确定双击DataGridViewCheckBox
有什么大惊小怪的。这不是 WPF,双击控件不会破坏任何数据绑定,它是 WinForms。双击可能不会在视觉上更新控件,但它不会破坏任何东西,在这种情况下,也许下面的解决方案是更好的解决方案。谢谢。
如果您将相同的代码从 CellContentClick
添加到 CellContentDoubleClick
中,这将非常有效。 CellMouseUp
即使选中了单元格但未单击复选框,也会触发 - 这是不希望的行为。
@torpidprey 或者只是为CellContentDoubleClick
设置CellContentClick
事件处理程序而不是复制,让这两个处理程序触发一个处理程序。您的解决方案修复了我的 winform 应用程序中的双击问题。【参考方案2】:
我发现@Killercam 的解决方案可以工作,但如果用户双击速度太快,就会有点狡猾。不确定其他人是否也发现了这种情况。我找到了另一个解决方案here。
它使用数据网格的CellValueChanged
和CellMouseUp
。长虹解释说
“原因是 OnCellvalueChanged 事件在 DataGridView 认为您已完成编辑之前不会触发。这对于 TextBox 列是有意义的,因为 OnCellvalueChanged 不会 [打扰] 为每个按键触发触发,但它不会对于 CheckBox 来说 [有意义]。”
这是他的例子:
private void myDataGrid_OnCellValueChanged(object sender, DataGridViewCellEventArgs e)
if (e.ColumnIndex == myCheckBoxColumn.Index && e.RowIndex != -1)
// Handle checkbox state change here
当它被点击时告诉复选框它完成编辑的代码,而不是等到用户离开该字段:
private void myDataGrid_OnCellMouseUp(object sender,DataGridViewCellMouseEventArgs e)
// End of edition on each click on column of checkbox
if (e.ColumnIndex == myCheckBoxColumn.Index && e.RowIndex != -1)
myDataGrid.EndEdit();
编辑:DoubleClick 事件与 MouseUp 事件分开处理。如果检测到 DoubleClick 事件,应用程序将完全忽略第一个 MouseUp 事件。除了 MouseUp 事件之外,还需要将这个逻辑添加到 CellDoubleClick 事件中:
private void myDataGrid_OnCellDoubleClick(object sender,DataGridViewCellEventArgs e)
// End of edition on each click on column of checkbox
if (e.ColumnIndex == myCheckBoxColumn.Index && e.RowIndex != -1)
myDataGrid.EndEdit();
【讨论】:
我遇到了响应者提到的双击问题,这个问题比第一个解决方案更有效。 我也遇到了双击问题,这个解决方案解决了。 点击“这里”按钮并查看文章。我在双击时遇到了同样的问题。 如果用空格键切换开关会怎样? 为了“修复”空格键问题,我在表单上将KeyPreview
设置为true,当e.KeyCode == Keys.Space
时,设置e.Handled = true
。换句话说,我只是禁用了键盘编辑。【参考方案3】:
jsturtevants 的解决方案效果很好。但是,我选择在 EndEdit 事件中进行处理。我更喜欢这种方法(在我的应用程序中),因为与 CellValueChanged 事件不同,EndEdit 事件不会在您填充网格时触发。
这是我的代码(其中一部分是从 jsturtevant 偷来的:
private void gridCategories_CellEndEdit(object sender, DataGridViewCellEventArgs e)
if (e.ColumnIndex == gridCategories.Columns["AddCategory"].Index)
//do some stuff
private void gridCategories_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
if (e.ColumnIndex == gridCategories.Columns["AddCategory"].Index)
gridCategories.EndEdit();
【讨论】:
好答案,但最好使用CellContentClick
而不是CellMouseUp
,因为后者将在用户单击单元格内的任何位置时调用,而前者仅在单击复选框时调用.【参考方案4】:
按照 Killercam 的回答,我的代码
private void dgvProducts_CellContentClick(object sender, DataGridViewCellEventArgs e)
dgvProducts.CommitEdit(DataGridViewDataErrorContexts.Commit);
和:
private void dgvProducts_CellValueChanged(object sender, DataGridViewCellEventArgs e)
if (dgvProducts.DataSource != null)
if (dgvProducts.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString() == "True")
//do something
else
//do something
【讨论】:
【参考方案5】:这也处理键盘激活。
private void dgvApps_CellContentClick(object sender, DataGridViewCellEventArgs e)
if(dgvApps.CurrentCell.GetType() == typeof(DataGridViewCheckBoxCell))
if (dgvApps.CurrentCell.IsInEditMode)
if (dgvApps.IsCurrentCellDirty)
dgvApps.EndEdit();
private void dgvApps_CellValueChanged(object sender, DataGridViewCellEventArgs e)
// handle value changed.....
【讨论】:
【参考方案6】:这里有一些代码:
private void dgvStandingOrder_CellContentClick(object sender, DataGridViewCellEventArgs e)
if (dgvStandingOrder.Columns[e.ColumnIndex].Name == "IsSelected" && dgvStandingOrder.CurrentCell is DataGridViewCheckBoxCell)
bool isChecked = (bool)dgvStandingOrder[e.ColumnIndex, e.RowIndex].EditedFormattedValue;
if (isChecked == false)
dgvStandingOrder.Rows[e.RowIndex].Cells["Status"].Value = "";
dgvStandingOrder.EndEdit();
private void dgvStandingOrder_CellEndEdit(object sender, DataGridViewCellEventArgs e)
dgvStandingOrder.CommitEdit(DataGridViewDataErrorContexts.Commit);
private void dgvStandingOrder_CurrentCellDirtyStateChanged(object sender, EventArgs e)
if (dgvStandingOrder.CurrentCell is DataGridViewCheckBoxCell)
dgvStandingOrder.CommitEdit(DataGridViewDataErrorContexts.Commit);
【讨论】:
这个答案包含正确的答案,它处理鼠标和键盘交互,以及重复交互而不离开单元格。但只需要最后一个处理程序——从CurrentCellDirtyStateChanged
调用CommitEdit
是整个解决方案。【参考方案7】:
都是编辑单元格,问题是单元格实际上没有编辑,所以你需要保存单元格或行的变化来获取点击复选框时的事件,这样你就可以使用功能:
datagridview.CommitEdit(DataGridViewDataErrorContexts.CurrentCellChange)
有了这个,你甚至可以在不同的事件中使用它。
【讨论】:
【参考方案8】:我找到了这个问题的更简单的答案。我只是使用反向逻辑。代码在 VB 中,但与 C# 没有太大区别。
Private Sub DataGridView1_CellContentClick(sender As Object, e As
DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick
Dim _ColumnIndex As Integer = e.ColumnIndex
Dim _RowIndex As Integer = e.RowIndex
'Uses reverse logic for current cell because checkbox checked occures
'after click
'If you know current state is False then logic dictates that a click
'event will set it true
'With these 2 check boxes only one can be true while both can be off
If DataGridView1.Rows(_RowIndex).Cells("Column2").Value = False And
DataGridView1.Rows(_RowIndex).Cells("Column3").Value = True Then
DataGridView1.Rows(_RowIndex).Cells("Column3").Value = False
End If
If DataGridView1.Rows(_RowIndex).Cells("Column3").Value = False And
DataGridView1.Rows(_RowIndex).Cells("Column2").Value = True Then
DataGridView1.Rows(_RowIndex).Cells("Column2").Value = False
End If
End Sub
最好的一点是不需要多个事件。
【讨论】:
【参考方案9】:我从这里尝试了一些答案,但我总是遇到某种问题(例如双击或使用键盘)。所以,我将其中一些结合起来,得到了一致的行为(它并不完美,但可以正常工作)。
void gridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
if(gridView.CurrentCell.GetType() != typeof(DataGridViewCheckBoxCell))
return;
if(!gridView.CurrentCell.IsInEditMode)
return;
if(!gridView.IsCurrentCellDirty)
return;
gridView.EndEdit();
void gridView_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
if(e.ColumnIndex == gridView.Columns["cFlag"].Index && e.RowIndex >= 0)
gridView.EndEdit();
void gridView_CellValueChanged(object sender, DataGridViewCellEventArgs e)
if(e.ColumnIndex != gridView.Columns["cFlag"].Index || e.RowIndex < 0)
return;
// Do your stuff here.
【讨论】:
【参考方案10】:Ben Voigt 在上面的评论回复中找到了最佳解决方案:
private void dgvStandingOrder_CurrentCellDirtyStateChanged(object sender, EventArgs e)
if (dgvStandingOrder.CurrentCell is DataGridViewCheckBoxCell)
dgvStandingOrder.CommitEdit(DataGridViewDataErrorContexts.Commit);
说真的,这就是你所需要的。
【讨论】:
【参考方案11】:对我有用的是CurrentCellDirtyStateChanged
结合datagridView1.EndEdit()
private void dataGridView1_CurrentCellDirtyStateChanged( object sender, EventArgs e )
if ( dataGridView1.CurrentCell is DataGridViewCheckBoxCell )
DataGridViewCheckBoxCell cb = (DataGridViewCheckBoxCell)dataGridView1.CurrentCell;
if ( (byte)cb.Value == 1 )
dataGridView1.CurrentRow.Cells["time_loadedCol"].Value = DateTime.Now.ToString();
dataGridView1.EndEdit();
【讨论】:
【参考方案12】:代码将在 DataGridView 中循环并检查 CheckBox 列是否被选中
private void dgv1_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
if (e.ColumnIndex == 0 && e.RowIndex > -1)
dgv1.CommitEdit(DataGridViewDataErrorContexts.Commit);
var i = 0;
foreach (DataGridViewRow row in dgv1.Rows)
if (Convert.ToBoolean(row.Cells[0].Value))
i++;
//Enable Button1 if Checkbox is Checked
if (i > 0)
Button1.Enabled = true;
else
Button1.Enabled = false;
【讨论】:
【参考方案13】:在 CellContentClick 事件中你可以使用这个策略:
private void myDataGrid_CellContentClick(object sender, DataGridViewCellEventArgs e)
if (e.ColumnIndex == 2)//set your checkbox column index instead of 2
//When you check
if (Convert.ToBoolean(myDataGrid.Rows[e.RowIndex].Cells[2].EditedFormattedValue) == true)
//EXAMPLE OF OTHER CODE
myDataGrid.Rows[e.RowIndex].Cells[5].Value = DateTime.Now.ToShortDateString();
//SET BY CODE THE CHECK BOX
myDataGrid.Rows[e.RowIndex].Cells[2].Value = 1;
else //When you decheck
myDataGrid.Rows[e.RowIndex].Cells[5].Value = String.Empty;
//SET BY CODE THE CHECK BOX
myDataGrid.Rows[e.RowIndex].Cells[2].Value = 0;
【讨论】:
【参考方案14】:我发现的最好方法(也不使用多个事件)是处理 CurrentCellDirtyStateChanged
事件。
private void dataGrid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
if (dataGridMatten.CurrentCell.OwningColumn == dataGridMatten.Columns["checkBoxColumn"] && dataGridMatten.IsCurrentCellDirty)
dataGrid.CommitEdit(DataGridViewDataErrorContexts.Commit);
//your code goes here
【讨论】:
这对我来说是醒的【参考方案15】:要在使用 devexpress xtragrid 时执行此操作,必须按照 here 的描述处理相应存储库项的 EditValueChanged 事件。调用 gridView1.PostEditor() 方法以确保已发布更改的值也很重要。这是一个实现:
private void RepositoryItemCheckEdit1_EditValueChanged(object sender, System.EventArgs e)
gridView3.PostEditor();
var isNoneOfTheAboveChecked = false;
for (int i = 0; i < gridView3.DataRowCount; i++)
if ((bool) (gridView3.GetRowCellValue(i, "NoneOfTheAbove")) && (bool) (gridView3.GetRowCellValue(i, "Answer")))
isNoneOfTheAboveChecked = true;
break;
if (isNoneOfTheAboveChecked)
for (int i = 0; i < gridView3.DataRowCount; i++)
if (!((bool)(gridView3.GetRowCellValue(i, "NoneOfTheAbove"))))
gridView3.SetRowCellValue(i, "Answer", false);
请注意,由于 xtragrid 不提供枚举器,因此必须使用 for 循环来遍历行。
【讨论】:
【参考方案16】:在单元格值更改后移除焦点允许在 DataGridView 中更新值。通过将 CurrentCell 设置为 null 来移除焦点。
private void DataGridView1OnCellValueChanged(object sender, DataGridViewCellEventArgs dataGridViewCellEventArgs)
// Remove focus
dataGridView1.CurrentCell = null;
// Put in updates
Update();
private void DataGridView1OnCurrentCellDirtyStateChanged(object sender, EventArgs eventArgs)
if (dataGridView1.IsCurrentCellDirty)
dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
【讨论】:
【参考方案17】:您可以在单击复选框后强制单元格提交值,然后捕获 CellValueChanged 事件。 CurrentCellDirtyStateChanged 在您单击复选框后立即触发。
以下代码适用于我:
private void grid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
SendKeys.Send("tab");
然后您可以将代码插入到 CellValueChanged 事件中。
【讨论】:
【参考方案18】:我将 DataGridView 与 VirtualMode=true 一起使用,只有这个选项对我有用 (当鼠标和空格键都在工作时,包括重复的空格键):
private void doublesGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e)
var data_grid = (DataGridView)sender;
if (data_grid.CurrentCell.IsInEditMode && data_grid.IsCurrentCellDirty)
data_grid.EndEdit();
private void doublesGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
if (e.ColumnIndex == CHECKED_COLUMN_NUM && e.RowIndex >= 0 && e.RowIndex < view_objects.Count) // view_objects - pseudocode
view_objects[e.RowIndex].marked = !view_objects[e.RowIndex].marked; // Invert the state of the displayed object
【讨论】:
【参考方案19】:这对我有用
private void employeeDataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
if (e.ColumnIndex == employeeDataGridView.Columns["employeeStatusColumn"].Index)
bool isChecked = (bool)employeeDataGridView.CurrentCell.Value;
if (isChecked)
MessageBox.Show("Checked " + isChecked); //out true;
else
MessageBox.Show("unChecked " + isChecked);
private void employeeDataGridView_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
if (employeeDataGridView.DataSource != null)
if (e.ColumnIndex == employeeDataGridView.Columns["employeeStatusColumn"].Index && e.RowIndex != -1)
employeeDataGridView.EndEdit();
【讨论】:
rawaha 欢迎来到 Stack Overflow!如果您可以添加对您的代码如何工作的描述,并可能解释这与该线程上提供的其他解决方案有何不同或更好,这将很有帮助。以上是关于如何检测 DataGridView CheckBox 事件变化?的主要内容,如果未能解决你的问题,请参考以下文章