Как обнаружить флажок элементом управления datagridview событие изменения?
у меня есть приложение winforms и я хочу вызвать некоторый код, когда флажок встроен в DataGridView контроль checked или unchecked. Каждое событие я пробовал либо
- срабатывает, как только
CheckBoxщелкается, но до того, как его проверенное состояние изменится, или - срабатывает только один раз
CheckBoxтеряет фокус
Я не могу найти событие, которое срабатывает сразу после того как проверил состояние изменения.
Edit:
то, что я пытаюсь достичь, это когда проверенное состояние a CheckBox в одном DataGridView изменения, данные в двух других DataGridViews изменения. Но все события, которые я использовал, данные в других сетках меняются только после CheckBox в первом DataGridView теряет фокус.
15 ответов:
обработки
DatGridViewsCheckedChangedсобытие вы должны сначала получитьCellContentClickогонь (который не имеетCheckBoxes текущее состояние!) тогда звоните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(); }Я надеюсь, что это помогает.
P. S. проверить эту статью https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged(v=vs. 110).aspx
Я нашел решение @Killercam для работы, но был немного изворотливым, если пользователь дважды щелкнул слишком быстро. Не уверен, что другие нашли, что дело тоже. Я нашел другое решение здесь.
Он использует в DataGrid
CellValueChangedиCellMouseUp. Чанхун объясняет, что" причиной этого является OnCellvalueChanged событие не будет срабатывать, пока DataGridView думает, что вы завершили редактирование. Это делает смысл для столбца текстового поля, как OnCellvalueChanged не будет [беспокоиться] стрелять для каждого ключевого удара, но это не [имеет смысла] для флажка."
вот он в действии из его примера:
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(); } }
решение 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(); } }
Это также обрабатывает активацию клавиатуры.
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..... }
после Killercam'Answer, мой код
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 } } }
все дело в редактировании ячейки, проблема в том, что ячейка не редактировалась на самом деле, поэтому вам нужно сохранить изменения ячейки или строки, чтобы получить событие, когда вы нажимаете флажок, чтобы вы могли использовать эту функцию:
datagridview.CommitEdit(DataGridViewDataErrorContexts.CurrentCellChange)при этом вы можете использовать его даже с другим событием.
Я нашел простой ответ на эту проблему. Я просто использую обратную логику. Код находится в 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одна из лучших вещей об этом нет необходимости для нескольких событий.
вот код:
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в сочетании с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(); }
код будет цикл в DataGridView и будет проверять, если флажок столбец проверен
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; } } }
в случае 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; } } }
для этого при использовании devexpress xtragrid необходимо обработать 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 для итерации по строкам.
Я нашел простой ответ на эту проблему. Я просто использую обратную логику. Код находится в VB, но он не сильно отличается от C#.
Private Sub DataGridView1_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick 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одна из лучших вещей об этом нет необходимости для нескольких событий.
удаление фокуса после изменения значения ячейки позволяет обновить значения в 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); } }
вы можете заставить клетки, чтобы зафиксировать значение, как только вы установите флажок, а затем поймать CellValueChanged событие. Элемент CurrentCellDirtyStateChanged срабатывает, как только вы установите флажок.
следующий код работает для меня:
private void grid_CurrentCellDirtyStateChanged(object sender, EventArgs e) { SendKeys.Send("{tab}"); }затем вы можете вставить свой код в CellValueChanged событие.