J'ai une application Winforms et je veux déclencher du code lorsqu'une case à cocher intégrée à un contrôle DataGridView
est cochée/décochée. Chaque événement que j'ai essayé soit
CheckBox
mais avant que son état vérifié change, ouCheckBox
perd son focusJe n'arrive pas à trouver un événement qui se déclenche immédiatement après le changement d'état coché.
Modifier:
Ce que j'essaie de faire, c'est que lorsque l'état vérifié d'une CheckBox
dans une DataGridView
change, les données de deux autres DataGridView
s changent. Pourtant, pour tous les événements que j'ai utilisés, les données des autres grilles ne sont modifiées qu'après la CheckBox
de la première DataGridView
perd le focus.
Pour gérer l'événement DatGridView
s CheckedChanged
, vous devez d'abord déclencher la CellContentClick
(qui n'a pas l'état actuel CheckBox
es!), Puis appeler CommitEdit
. Cela déclenchera à son tour l'événement CellValueChanged
que vous pourrez utiliser pour effectuer votre travail. Ceci est un oubli de Microsoft. Faites quelque chose comme ce qui suit ...
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();
}
J'espère que ça aide.
P.S. Consultez cet article https://msdn.Microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged(v=vs.110).aspx
La solution de @ Killercam fonctionnait bien, mais j'étais un peu louche si l'utilisateur double-cliquait trop rapidement. Je ne sais pas si les autres ont trouvé que le cas non plus. J'ai trouvé une autre solution ici .
Il utilise les variables CellValueChanged
et CellMouseUp
de la grille de données. Changhong explique que
"La raison en est que l'événement OnCellvalueChanged ne se déclenchera pas tant que le DataGridView n'aura pas terminé l'édition. Cela donne un sens à une colonne TextBox, car OnCellvalueChanged ne se déclenche pas à chaque frappe, mais ce n'est pas le cas [ logique] pour un CheckBox ".
Ici, il est en action 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 que l'édition est terminée lorsque l'utilisateur clique dessus, 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 très bien fonctionné. Cependant, j'ai choisi d'effectuer 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 grille.
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.ToString() == "True")
{
//do something
}
else
{
//do something
}
}
}
Voici du 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);
}
}
J'ai trouvé une réponse plus simple à ce problème. J'utilise simplement la logique inverse. Le code est dans 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 la nécessité de plusieurs événements.
Il s’agit de modifier la cellule. Le problème, c’est que la cellule n’a pas été modifiée, vous devez donc enregistrer les modifications de la cellule ou de la ligne pour obtenir l’événement lorsque vous cochez la case pour pouvoir utiliser cette fonction:
datagridview.CommitEdit(DataGridViewDataErrorContexts.CurrentCellChange)
avec cela, vous pouvez l'utiliser même avec un événement différent.
Dans le cas où 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.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;
}
}
}
Le code bouclera 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;
}
}
}
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.ToString();
}
}
dataGridView1.EndEdit();
}
Supprimer le focus après les changements de valeur de cellule permet aux valeurs de se mettre à jour dans DataGridView. Supprimez le focus en définissant le 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);
}
}
Pour ce faire, lorsque vous utilisez xtragrid devexpress, 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, comme xtragrid ne fournit pas d’énumérateur, il est nécessaire d’utiliser une boucle for pour effectuer une itération sur les lignes.
Vous pouvez forcer la cellule à valider la valeur dès que vous cliquez sur la case à cocher, puis attrapez l'événement CellValueChanged . Le CurrentCellDirtyStateChanged se déclenche dès que vous cochez la case.
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 .
J'ai trouvé une réponse plus simple à ce problème. J'utilise simplement la logique inverse. Le code est dans 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 la nécessité de plusieurs événements.
J'ai essayé quelques réponses à partir de là, mais j'ai toujours eu une sorte de problème (comme un double clic ou en utilisant le clavier). J'ai donc combiné certains d'entre eux et obtenu un comportement cohérent (ce n'est pas parfait, mais ça fonctionne correctement).
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.
}