Как определить событие EventGridView CheckBox?
У меня есть приложение winforms и вы хотите запустить какой-либо код, когда флажок, встроенный в элемент управления DataGridView
, проверяется/не проверяется. Каждое событие, которое я пробовал либо
- Триггеры, как только нажимается
CheckBox
, но до того, как оно будет изменено, или
- Триггеры только один раз, когда
CheckBox
теряет фокус
Я не могу найти событие, которое срабатывает сразу после изменения состояния проверки.
Edit:
То, что я пытаюсь достичь, заключается в том, что когда измененное состояние CheckBox
в одном DataGridView
изменяется, данные в двух других DataGridView
изменяются. Но все события, которые я использовал, данные в других сетках меняются только после того, как CheckBox
в первом DataGridView
теряет фокус.
Ответы
Ответ 1
Чтобы обработать событие DatGridView
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();
}
Надеюсь, это поможет.
P.S. Проверьте эту статью https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged(v=vs.110).aspx
Ответ 2
Я нашел решение @Killercam для работы, но было немного изворотливым, если пользователь дважды щелкнул слишком быстро. Не уверен, что другие обнаружили, что дело. Я нашел другое решение здесь.
Он использует datagrid 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();
}
}
Ответ 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();
}
}
Ответ 4
Это также относится к активации клавиатуры.
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.....
}
Ответ 5
Вот какой код:
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);
}
}
Ответ 6
после Killercam'answer, My code
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
}
}
}
Ответ 7
Все о редактировании ячейки, проблема, которая является ячейкой, фактически не редактировалась, поэтому вам нужно сохранить изменения ячейки или строки, чтобы получить событие, когда вы нажмете этот флажок, чтобы вы могли использовать эту функция:
datagridview.CommitEdit(DataGridViewDataErrorContexts.CurrentCellChange)
с этим вы можете использовать его даже с другим событием.
Ответ 8
Я нашел более простой ответ на эту проблему. Я просто использую обратную логику. Код находится в VB, но он не сильно отличается от С#.
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
Что сработало для меня, было 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();
}
Ответ 10
Код будет зацикливаться в DataGridView и проверяет, проверен ли CheckBox Column
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;
}
}
}
Ответ 11
В случае 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;
}
}
}
Ответ 12
Чтобы сделать это при использовании 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 для итерации по строкам.
Ответ 13
Я нашел более простой ответ на эту проблему. Я просто использую обратную логику. Код находится в VB, но он не сильно отличается от С#.
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
Одна из лучших вещей в этом случае не нужна для нескольких событий.
Ответ 14
Удаление фокуса после изменения значения ячейки позволяет обновлять значения в 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);
}
}
Ответ 15
Вы можете заставить ячейку зафиксировать значение, как только вы установите флажок, а затем поймаете событие CellValueChanged. CurrentCellDirtyStateChanged срабатывает, как только вы нажимаете этот флажок.
Следующий код работает для меня:
private void grid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
SendKeys.Send("{tab}");
}
Затем вы можете вставить свой код в событие CellValueChanged.
Ответ 16
Я попробовал некоторые ответы отсюда, но у меня всегда были какие-то проблемы (например, двойной щелчок или использование клавиатуры). Итак, я объединил некоторые из них и получил последовательное поведение (оно не идеально, но работает правильно).
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.
}