在 DataGridView 中触发复选框值更改事件
Posted
技术标签:
【中文标题】在 DataGridView 中触发复选框值更改事件【英文标题】:Triggering a checkbox value changed event in DataGridView 【发布时间】:2010-10-30 05:50:12 【问题描述】:我有一个带有复选框列的网格视图,我想在切换单元格的值后立即触发绘图事件。我尝试了 ValueChaged 和 CellEndEdit 和 BeginEdit,并选择了选择模式为 CellSelect。至于前两个事件,该事件是在编辑模式结束时触发的,比如移出当前单元格,或者来回移动。这只是一种奇怪的行为。
一旦单元格值更改,是否有任何东西会触发网格视图上的事件?
【问题讨论】:
【参考方案1】:我使用 CellContentClick 事件,它确保用户点击了复选框。即使用户留在同一个单元格中,它也会触发多次。一个问题是 Value 没有得到更新,并且对于未选中总是返回“false”。诀窍是使用单元格的 .EditedFormattedValue 属性而不是 Value 属性。 EditedFormattedValue 将使用复选标记进行跟踪,并且是在触发 CellContentClick 时希望 Value 包含在其中的内容。
不需要计时器,不需要任何花哨的东西,只需使用 CellContentClick 事件并检查 EditedFormattedValue 来判断复选框正在进入/刚刚进入的状态。如果 EditedFormattedValue = true,则复选框被选中。
【讨论】:
【参考方案2】:我的一位同事建议捕获 CurrentCellDirtyStateChanged 事件。见http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged.aspx。
【讨论】:
将其与 datagridview.EndEdit() 结合并更新绑定数据 对我来说这是正确的事件。结合 DataGridViewName.EndEdit() 。谢谢解决方案 我应用了这段代码。但是表格的值只会在我进行额外动作时更新(例如滚动网格视图、单击单元格、调整列大小或任何其他动作)。请告诉我发生了什么事?【参考方案3】:另一种方法是处理 CellContentClick 事件(它不会为您提供单元格的 Value 属性中的当前值),调用 grid.CommitEdit(DataGridViewDataErrorContexts.Commit) 来更新值,这反过来会在您可以触发的地方触发 CellValueChanged然后获取实际的(即正确的)DataGridViewCheckBoxColumn 值。
private void grid_CellContentClick(object sender, DataGridViewCellEventArgs e)
grid.CommitEdit(DataGridViewDataErrorContexts.Commit);
private void grid_CellValueChanged(object sender, DataGridViewCellEventArgs e)
// do something with grid.Rows[e.RowIndex].Cells[e.ColumnIndex].Value
目标 .NET 框架:2.0
【讨论】:
我应用了这段代码。但是只有当我进行额外的动作(例如滚动网格视图、单击单元格、调整列大小或任何其他动作)时才会执行 cellValueChanged 事件。请告诉我发生了什么事?【参考方案4】:尝试挂钩 CellContentClick 事件。 DataGridViewCellEventArgs 将有一个 ColumnIndex 和一个 RowIndex,因此您可以知道是否确实单击了 ChecboxCell。这个事件的好处是它只会在实际的复选框本身被点击时触发。如果单击复选框周围单元格的白色区域,它将不会触发。这样,您几乎可以保证在此事件触发时复选框值已更改。然后,您可以调用 Invalidate() 来触发绘图事件,也可以调用 EndEdit() 来触发行编辑的结束(如果需要)。
【讨论】:
但仍必须取消选择单元格才能触发此事件。因此,如果您停留在同一个单元格中并且单击它不止一次,则不会触发该事件【参考方案5】:我终于这样实现了
private void dataGridView1_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
if (e.ColumnIndex >= 0 && e.RowIndex >= 0)
if (dataGridView1[e.ColumnIndex, e.RowIndex].GetContentBounds(e.RowIndex).Contains(e.Location))
cellEndEditTimer.Start();
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
/*place your code here*/
private void cellEndEditTimer_Tick(object sender, EventArgs e)
dataGridView1.EndEdit();
cellEndEditTimer.Stop();
【讨论】:
【参考方案6】:我遇到了同样的问题,但想出了一个不同的解决方案:
如果您将列或整个网格设置为“只读”,这样当用户单击复选框时它不会更改值。
幸运的是,DataGridView.CellClick
事件仍然被触发。
就我而言,我在 cellClick
事件中执行以下操作:
if (jM_jobTasksDataGridView.Columns[e.ColumnIndex].CellType.Name == "DataGridViewCheckBoxCell")
但如果您有多个复选框列,则可以检查列名。
然后我自己进行数据集的所有修改/保存。
【讨论】:
【参考方案7】:小更新....确保您使用EditedFormattedValue
而不是value
,因为我尝试过value
,但它永远不会给出正确的状态,即已选中/未选中大多数站点仍然使用value
,但已使用在最新的 c# 2010 express 下面是一种访问方式..
grdJobDetails.Rows[e.RowIndex].Cells[0].EditedFormattedValue
此外,少数人建议或使用的_CellValueChanged
事件必须在某些情况下可用,但如果您正在寻找对单元格的每次检查/取消检查,请确保使用_CellContentClick
,否则根据我的通知,我并非每次都看到_CellValueChanged
被触发..如果相同的复选框被反复点击,它不会触发_CellValueChanged
,但如果你交替点击,例如你有两个复选框并在另一个_CellValueChanged
事件之后点击一个,但通常如果寻找每次选中/取消选中任何单元格时都会触发事件 _CellValueChanged
不会触发。
【讨论】:
【参考方案8】:“EditingControlShowing”事件不会在复选框值更改时触发。因为复选框单元格的显示样式没有改变。
我使用的解决方法如下。 (我用过 CellContentClick 事件)
private void gGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
if (string.Compare(gGridView1.CurrentCell.OwningColumn.Name, "CheckBoxColumn") == 0)
bool checkBoxStatus = Convert.ToBoolean(gGridView1.CurrentCell.EditedFormattedValue);
//checkBoxStatus gives you whether checkbox cell value of selected row for the
//"CheckBoxColumn" column value is checked or not.
if(checkBoxStatus)
//write your code
else
//write your code
以上对我有用。如果需要更多帮助,请告诉我。
【讨论】:
【参考方案9】:我找到了一个简单的解决方案。
单击单元格后只需更改单元格焦点。
private void DGV_CellContentClick(object sender, DataGridViewCellEventArgs e)
if (e.ColumnIndex == "Here checkbox column id or name")
DGV.Item(e.ColumnIndex, e.RowIndex + 1).Selected = true;
//Here your code
不要忘记检查 (ckeckbox + 1) 索引的列是否存在。
【讨论】:
【参考方案10】:CellClick
和CellMouseClick
的每个答案都是错误的,因为您可以使用键盘更改单元格的值,并且不会触发事件。此外,CurrentCellDirtyStateChanged
只会触发一次,这意味着如果您多次选中/取消选中同一个框,您只会得到一个事件。结合上面的几个答案给出以下简单的解决方案:
private void dgvList_CurrentCellDirtyStateChanged(object sender, EventArgs e)
if (dgvList.CurrentCell is DataGridViewCheckBoxCell)
dgvList.CommitEdit(DataGridViewDataErrorContexts.Commit);
private void dgvList_CellValueChanged(object sender, DataGridViewCellEventArgs e)
// Now this will fire immediately when a check box cell is changed,
// regardless of whether the user uses the mouse, keyboard, or touchscreen.
//
// Value property is up to date, you DO NOT need EditedFormattedValue here.
【讨论】:
【参考方案11】:cellEndEditTimer.Start();
这一行使 datagridview 更新复选框列表
谢谢。
【讨论】:
此答案需要将其他组件添加到表单中,并且不能单独使用。为了使这个回答完整,您需要通知用户他们需要在表单中添加一个计时器,并且您还应该提供计时器的_Tick
事件的代码。【参考方案12】:
我发现前两个答案的组合满足了我的需求。我使用了 CurrentCellDirtyStateChanged 事件并检查了 EditedFormattedValue。
private void dgv_CurrentCellDirtyStateChanged(object sender, EventArgs e)
DataGridView dgv = (DataGridView)sender;
DataGridViewCell cell = dgv.CurrentCell;
if (cell.RowIndex >= 0 && cell.ColumnIndex == 3) // My checkbox column
// If checkbox checked, copy value from col 1 to col 2
if (dgv.Rows[cell.RowIndex].Cells[cell.ColumnIndex].EditedFormattedValue != null && dgv.Rows[cell.RowIndex].Cells[cell.ColumnIndex].EditedFormattedValue.Equals(true))
dgv.Rows[cell.RowIndex].Cells[1].Value = dgv.Rows[cell.RowIndex].Cells[2].Value;
【讨论】:
【参考方案13】:当您想在 DataGrid 视图中使用 checkedChanged
事件时,请使用此代码:
private void grdBill_CellContentClick(object sender, DataGridViewCellEventArgs e)
grdBill.CurrentCell = grdBill.Rows[grdBill.CurrentRow.Index].Cells["gBillNumber"];
private void grdBill_CellEndEdit(object sender, DataGridViewCellEventArgs e)
calcBill();
private void calcBill()
listBox1.Items.Clear();
for (int i = 0; i < grdBill.Rows.Count - 1; i++)
if (Convert.ToBoolean(grdBill.Rows[i].Cells["gCheck"].Value) == true)
listBox1.Items.Add(grdBill.Rows[i].Cells["gBillNumber"].Value.ToString());
这里,grdBill = DataGridView1, gCheck = CheckBox in GridView(First Column), gBillNumber = TextBox
在网格(第二列)中。
所以,当我们想要为每次点击触发 checkchanged 事件时,首先执行 CellContentClick,当用户点击文本框时它会触发,然后它将当前单元格移动到下一列,因此 CellEndEdit 列会触发,它将检查复选框是否被选中并在列表框中添加“gBillNumber”(在函数calcBill中)。
【讨论】:
【参考方案14】:使用未绑定的控件(即我以编程方式管理内容),没有 EndEdit() 它只调用 CurrentCellDirtyStateChanged 一次,然后再也不会;但我发现使用 EndEdit() CurrentCellDirtyStateChanged 被调用了两次(第二次可能是由 EndEdit() 引起的,但我没有检查),所以我做了以下,这对我来说效果最好:
bool myGridView_DoCheck = false;
private void myGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e)
if (!myGridView_DoCheck)
myGridView_DoCheck = true;
myGridView.EndEdit();
// do something here
else
myGridView_DoCheck = false;
【讨论】:
【参考方案15】:使用 .EditedFormattedValue 属性可以解决问题
要在每次单击单元格中的复选框切换值时收到通知,您可以使用 CellContentClick 事件并访问初始单元格值 .EditedFormattedValue。
在触发事件时,.EditedFormattedValue 尚未在视觉上应用于复选框,也尚未提交给 .Value 属性。
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
var checkbox = dataGridView1.CurrentCell as DataGridViewCheckBoxCell;
bool isChecked = (bool)checkbox.EditedFormattedValue;
事件在每次点击时触发,.EditedFormattedValue 切换
【讨论】:
以上是关于在 DataGridView 中触发复选框值更改事件的主要内容,如果未能解决你的问题,请参考以下文章
将包含文本值“true”文本的 datagridview 单元格类型更改为复选框
winform中datagridview怎么添加行之后将焦点选中在新添加的行?