saber - manejo de checkbox en datagridview c#
Cómo detectar el cambio de evento DataGridView CheckBox? (15)
Tengo una aplicación de winforms y quiero activar algún código cuando una casilla de verificación incrustada en un control DataGridView
está marcada / desmarcada. Cada evento que he probado
- Desencadena tan pronto como se hace clic en
CheckBox
pero antes de que su estado verificado cambie, o - Dispara solo cuando el
CheckBox
pierde su foco
Parece que no puedo encontrar un evento que se active inmediatamente después de que el estado verificado cambie.
Editar:
Lo que intento lograr es que cuando el estado comprobado de un CheckBox
en un DataGridView
cambie, los datos en otros dos DataGridView
cambien. Sin embargo, todos los eventos que he usado, los datos en las otras grillas solo cambian después de que el CheckBox
en el primer DataGridView
pierde el foco.
Aquí hay un código:
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);
}
}
El Código hará un bucle en DataGridView y comprobará si la columna CheckBox está marcada
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;
}
}
}
En el caso de CellContentClick puede usar esta estrategia:
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;
}
}
}
Encontré que la solución de @ Killercam funciona, pero era un poco dudosa si el usuario hacía doble clic demasiado rápido. No estoy seguro de si otros encontraron que el caso tampoco. Encontré una solución más here .
Utiliza CellValueChanged
y CellMouseUp
la cuadrícula de CellMouseUp
. Changhong explica eso
"La razón de esto es que el evento OnCellvalueChanged no se disparará hasta que DataGridView piense que usted ha completado la edición. Esto hace que los sentidos para una columna TextBox, como OnCellvalChanged no se dispare por cada golpe de tecla, pero no lo hace [ tiene sentido] para un CheckBox ".
Aquí está en acción por su ejemplo:
private void myDataGrid_OnCellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == myCheckBoxColumn.Index && e.RowIndex != -1)
{
// Handle checkbox state change here
}
}
Y el código para indicar a la casilla de verificación que está haciendo la edición cuando se hace clic, en lugar de esperar hasta que el usuario abandone el campo:
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();
}
}
Esto también maneja la activación del teclado.
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.....
}
He encontrado una respuesta más simple a este problema. Simplemente uso la lógica inversa. El código está en VB pero no es muy diferente 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
Una de las mejores cosas sobre esto es que no hay necesidad de eventos múltiples.
He encontrado una respuesta más simple a este problema. Simplemente uso la lógica inversa. El código está en VB pero no es muy diferente 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
Una de las mejores cosas sobre esto es que no hay necesidad de eventos múltiples.
La eliminación del enfoque después de que el valor de la celda cambie permite que los valores se actualicen en DataGridView. Elimine el foco configurando CurrentCell en nulo.
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);
}
}
La solución de jsturtevants funcionó muy bien. Sin embargo, opté por hacer el procesamiento en el evento EndEdit. Prefiero este enfoque (en mi aplicación) porque, a diferencia del evento CellValueChanged, el evento EndEdit no se dispara mientras está poblando la cuadrícula.
Aquí está mi código (parte del cual es robado de 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();
}
}
Lo que funcionó para mí fue CurrentCellDirtyStateChanged
en combinación con 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();
}
Para hacer esto cuando se usa devexpress xtragrid, es necesario manejar el evento EditValueChanged de un elemento de repositorio correspondiente como se describe here . También es importante llamar al método gridView1.PostEditor () para garantizar que el valor modificado se haya publicado. Aquí hay una implementación:
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);
}
}
}
}
Tenga en cuenta que debido a que xtragrid no proporciona un enumerador, es necesario usar un ciclo for para iterar sobre las filas.
Para manejar el evento CheckedChanged
, primero debe hacer que CellContentClick
(¡que no tiene el estado actual de CheckBox
es!) Y luego llamar a CommitEdit
. Esto activará el evento CellValueChanged
que puede usar para hacer su trabajo. Esto es un descuido de Microsoft . Haga algo como lo siguiente ...
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();
}
Espero que esto ayude.
PS Verifique este artículo https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged(v=vs.110).aspx
Puede forzar a la celda a confirmar el valor tan pronto como haga clic en la casilla de verificación y luego atrapar el evento CellValueChanged . CurrentCellDirtyStateChanged se activa tan pronto como hace clic en la casilla de verificación.
El siguiente código funciona para mí:
private void grid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
SendKeys.Send("{tab}");
}
Luego puede insertar su código en el evento CellValueChanged .
Se trata de editar la celda, el problema es que la celda no se editó en realidad, por lo que debe guardar los cambios de la celda o la fila para obtener el evento cuando haga clic en la casilla de verificación para poder usar esta función:
datagridview.CommitEdit(DataGridViewDataErrorContexts.CurrentCellChange)
con esto puedes usarlo incluso con un evento diferente.
siguiendo Killercam''answer, Mi código
private void dgvProducts_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
dgvProducts.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
y:
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
}
}
}