Comment détecter le changement d’événement DataGridView CheckBox?

J’ai une application winforms et je veux déclencher du code lorsqu’une case à cocher incorporée dans un contrôle DataGridView est cochée / décochée. Chaque événement que j’ai essayé soit

  1. Déclenche dès que l’on clique sur la case à cocher, mais avant que son état vérifié ne change, ou
  2. Déclenche uniquement une fois que le CheckBox perd le focus

Je n’arrive pas à trouver un événement qui se déclenche immédiatement après le changement d’état vérifié.


Modifier:

Ce que j’essaie de faire, c’est que lorsque l’état vérifié d’un contrôle CheckBox dans un DataGridView change, les données de deux autres DataGridView s changent. Pourtant, tous les événements que j’ai utilisés, les données dans les autres grids ne changent que lorsque le CheckBox du premier DataGridView perd le focus.

Pour gérer l’événement CheckedChanged , vous devez d’abord CellContentClick (qui n’a pas l’état actuel de CheckBox !), Puis appeler CommitEdit . Cela déclenche à son tour l’événement CellValueChanged que vous pouvez utiliser pour effectuer votre travail. C’est un oubli de Microsoft . Faites quelque chose comme le suivant …

 private void dataGridViewSites_CellContentClick(object sender, DataGridViewCellEventArgs e) { dataGridViewSites.CommitEdit(DataGridViewDataErrorContexts.Commit); } ///  /// Works with the above. ///  private void dataGridViewSites_CellValueChanged(object sender, DataGridViewCellEventArgs e) { UpdateDataGridViewSite(); } 

J’espère que ça aide.

PS Consultez cet article https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged(v=vs.110).aspx

J’ai trouvé la solution de @ Killercam au travail mais elle était un peu bizarre si l’utilisateur cliquait deux fois trop vite. Pas sûr si les autres ont trouvé le cas non plus. J’ai trouvé une autre solution ici .

Il utilise CellValueChanged et CellMouseUp la grid de données. Changhong explique que

“La raison en est que l’événement OnCellvalueChanged ne se déclenche pas tant que DataGridView ne pense pas avoir terminé les modifications. Cela prend tout son sens pour une colonne TextBox, car OnCellvalueChanged ne se déclencherait pas pour chaque frappe de clé, mais pas [ est logique] pour un CheckBox. ”

Ici, il est en action à partir de son exemple:

 private void myDataGrid_OnCellValueChanged(object sender, DataGridViewCellEventArgs e) { if (e.ColumnIndex == myCheckBoxColumn.Index && e.RowIndex != -1) { // Handle checkbox state change here } } 

Et le code pour indiquer à la case à cocher qu’il a été modifié lorsqu’il est cliqué, au lieu d’attendre que l’utilisateur quitte le champ:

 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(); } } 

La solution de Jsturtevants a bien fonctionné. Cependant, j’ai opté pour le traitement dans l’événement EndEdit. Je préfère cette approche (dans mon application) car, contrairement à l’événement CellValueChanged, l’événement EndEdit ne se déclenche pas lorsque vous remplissez la grid.

Voici mon code (dont une partie est volée à 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(); } } 

Cela gère également l’activation du clavier.

  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..... } 

suite à Killercam’answer, Mon code

 private void dgvProducts_CellContentClick(object sender, DataGridViewCellEventArgs e) { dgvProducts.CommitEdit(DataGridViewDataErrorContexts.Commit); } 

et :

 private void dgvProducts_CellValueChanged(object sender, DataGridViewCellEventArgs e) { if (dgvProducts.DataSource != null) { if (dgvProducts.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToSsortingng() == "True") { //do something } else { //do something } } } 

Il s’agit de modifier la cellule, le problème qui est la cellule n’a pas modifié en fait, vous devez donc enregistrer les modifications de la cellule ou de la ligne pour obtenir l’événement lorsque vous cliquez sur la case à cocher afin que vous puissiez utiliser cette fonction:

 datagridview.CommitEdit(DataGridViewDataErrorContexts.CurrentCellChange) 

avec cela, vous pouvez l’utiliser même avec un événement différent.

J’ai trouvé une réponse plus simple à ce problème. J’utilise simplement la logique inverse. Le code est en VB mais il n’est pas très différent de 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 

L’une des meilleures choses à ce sujet n’est pas nécessaire pour plusieurs événements.

Voici un 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); } } 

Ce qui a fonctionné pour moi était CurrentCellDirtyStateChanged en combinaison avec 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.ToSsortingng(); } } dataGridView1.EndEdit(); } 

Le code fera une boucle dans DataGridView et vérifiera si la colonne CheckBox est cochée

 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; } } } 

Dans l’événement CellContentClick, vous pouvez utiliser cette stratégie:

 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.ToShortDateSsortingng(); //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 = Ssortingng.Empty; //SET BY CODE THE CHECK BOX myDataGrid.Rows[e.RowIndex].Cells[2].Value = 0; } } } 

Pour ce faire, lorsque vous utilisez devexpress xtragrid, il est nécessaire de gérer l’événement EditValueChanged d’un élément de référentiel correspondant, comme décrit ici . Il est également important d’appeler la méthode gridView1.PostEditor () pour vérifier que la valeur modifiée a été publiée. Voici une implémentation:

  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); } } } } 

Notez que parce que xtragrid ne fournit pas d'énumérateur, il est nécessaire d'utiliser une boucle for pour parcourir les lignes.

J’ai trouvé une réponse plus simple à ce problème. J’utilise simplement la logique inverse. Le code est en VB mais il n’est pas très différent de 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 

L’une des meilleures choses à ce sujet n’est pas nécessaire pour plusieurs événements.

La suppression du focus après les modifications de la valeur de cellule permet aux valeurs de se mettre à jour dans DataGridView. Supprimez le focus en définissant CurrentCell sur 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); } } 

Vous pouvez forcer la cellule à valider la valeur dès que vous cliquez sur la case à cocher, puis interceptez l’événement CellValueChanged . Le CurrentCellDirtyStateChanged se déclenche dès que vous cliquez sur la case à cocher.

Le code suivant fonctionne pour moi:

 private void grid_CurrentCellDirtyStateChanged(object sender, EventArgs e) { SendKeys.Send("{tab}"); } 

Vous pouvez ensuite insérer votre code dans l’événement CellValueChanged .