У меня есть приложение winforms, и я хочу запустить какой-то код, когда установлен или снят флажок, встроенный в элемент DataGridView
управления. Каждое мероприятие, которое я пробовал
- Срабатывает, как только
CheckBox
щелкают, но до того, как его отмеченное состояние изменится, или - Срабатывает только после того, как
CheckBox
теряет фокус
Кажется, я не могу найти событие, которое срабатывает сразу после изменения отмеченного состояния.
Редактировать:
Я пытаюсь добиться того, чтобы при изменении отмеченного состояния CheckBox
в одном DataGridView
изменяются данные в двух других DataGridView
. Тем не менее, все события, которые я использовал, данные в других сетках меняются только после того, CheckBox
как первая DataGridView
теряет фокус.
CurrentCellDirtyStateChanged
событие?Ответы:
Чтобы обработать событие
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(); }
Надеюсь, это поможет.
PS Проверьте эту статью https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged(v=vs.110).aspx
источник
DataGridViewCheckBox
заключается суета о двойном щелчке по a . Это не WPF, и двойной щелчок по элементу управления не нарушает привязку данных, это WinForms. Двойной щелчок может не обновить элемент управления визуально, но он ничего не сломает, и в этом случае, возможно, решение, приведенное ниже, является лучшим. Благодарю.CellContentClick
вCellContentDoubleClick
.CellMouseUp
is будет срабатывать, даже если ячейка выбрана, но флажок не установлен, что является нежелательным поведением.Я обнаружил, что решение @Killercam работает, но было немного хитро, если пользователь дважды щелкал слишком быстро. Не уверен, что и другие нашли это так. Я нашел другое решение здесь .
Он использует сетку данных
CellValueChanged
иCellMouseUp
. Чанхун объясняет, чтоВот это действие из его примера:
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. Эту логику необходимо добавить в событие CellDoubleClick в дополнение к событию MouseUp:
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
to true on the form and whene.KeyCode == Keys.Space
, sete.Handled = true
. In other words, I just disabled keyboard editing.jsturtevants's solution worked great. However, I opted to do the processing in the EndEdit event. I prefer this approach (in my application) because, unlike the CellValueChanged event, the EndEdit event does not fire while you are populating the grid.
Here is my code (part of which is stolen from 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
instead ofCellMouseUp
because the latter will be called when the user clicks anywhere inside the cell whereas the former is only called when the checkbox is clicked.This also handles the keyboard activation.
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..... }
источник
following Killercam'answer, My code
private void dgvProducts_CellContentClick(object sender, DataGridViewCellEventArgs e) { dgvProducts.CommitEdit(DataGridViewDataErrorContexts.Commit); }
and :
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 } } }
источник
Here is some code:
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); } }
источник
CommitEdit
fromCurrentCellDirtyStateChanged
is the whole solution.It's all about editing the cell, the problem that is the cell didn't edited actually, so you need to save The changes of the cell or the row to get the event when you click the check box so you can use this function:
with this you can use it even with a different event.
источник
I have found a simpler answer to this problem. I simply use reverse logic. The code is in VB but it is not much different than 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
One of the best things about this is no need for multiple events.
источник
What worked for me was
CurrentCellDirtyStateChanged
in combination withdatagridView1.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(); }
источник
The Code will loop in DataGridView and Will check if CheckBox Column is Checked
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; } } }
источник
In the event CellContentClick you can use this strategy:
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; } } }
источник
I've tried some answers from here, but I've always had some kind of problem (like double clicking or using the keyboard). So, I combined some of them and got a consistent behavior (it's not perfect, but works properly).
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. }
источник
To do this when using the devexpress xtragrid, it is necessary to handle the EditValueChanged event of a corresponding repository item as described here. It is also important to call the gridView1.PostEditor() method to ensure the changed value has been posted. Here is an implementation:
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); } } } }
Note that because the xtragrid doesnt provide an enumerator it is necessary to use a for loop to iterate over rows.
источник
Removing the focus after the cell value changes allow the values to update in the DataGridView. Remove the focus by setting the CurrentCell to 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); } }
источник
You can force the cell to commit the value as soon as you click the checkbox and then catch the CellValueChanged event. The CurrentCellDirtyStateChanged fires as soon as you click the checkbox.
The following code works for me:
private void grid_CurrentCellDirtyStateChanged(object sender, EventArgs e) { SendKeys.Send("{tab}"); }
You can then insert your code in the CellValueChanged event.
источник
Ben Voigt found the best solution in a comment-reply above:
private void dgvStandingOrder_CurrentCellDirtyStateChanged(object sender, EventArgs e) { if (dgvStandingOrder.CurrentCell is DataGridViewCheckBoxCell) dgvStandingOrder.CommitEdit(DataGridViewDataErrorContexts.Commit); }
Seriously, that's ALL you need.
источник
I use DataGridView with VirtualMode=true and only this option worked for me (when both the mouse and the space bar are working, including repeated space clicks):
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 } }
источник