Tengo una aplicación winforms y quiero activar algún código cuando una casilla de verificación incrustada en un DataGridView
control está marcada / desmarcada. Cada evento que he probado
- Se activa tan pronto como
CheckBox
se hace clic en pero antes de que cambie su estado marcado, o - Se dispara solo una vez que
CheckBox
pierde su enfoque
Parece que no puedo encontrar un evento que se active inmediatamente después de que cambie el estado verificado.
Editar:
Lo que estoy tratando de lograr es que cuando el estado verificado de a CheckBox
en uno DataGridView
cambia, los datos en otros dos DataGridView
cambian. Sin embargo, todos los eventos que he usado, los datos en las otras cuadrículas solo cambian después de que CheckBox
en la primera DataGridView
pierde el foco.
c#
winforms
datagridview
PJW
fuente
fuente
CurrentCellDirtyStateChanged
Evento?Respuestas:
Para manejar el evento
DatGridView
sCheckedChanged
, primero debe hacerCellContentClick
que se dispare (¡que no tiene elCheckBox
estado actual es!) Y luego llamarCommitEdit
. Esto, a su vez, activará elCellValueChanged
evento que puede utilizar para hacer su trabajo. Este es un descuido de Microsoft . Haz 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 Consulte este artículo https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged(v=vs.110).aspx
fuente
DataGridViewCheckBox
. Esto no es WPF y hacer doble clic en el control no rompe ningún enlace de datos, es WinForms. Es posible que hacer doble clic no actualice el control visualmente, pero no rompe nada y, en este caso, quizás la solución a continuación sea la mejor. Gracias.CellContentClick
dentroCellContentDoubleClick
.CellMouseUp
Se activará incluso si la celda está seleccionada pero no se hace clic en la casilla de verificación, lo que no es el comportamiento deseado.Encontré que la solución de @Killercam funcionaba, pero era un poco dudosa si el usuario hacía doble clic demasiado rápido. No estoy seguro si otros también encontraron ese caso. Encontré otra solución aquí .
Utiliza las redes de datos
CellValueChanged
yCellMouseUp
. Changhong explica queAquí está en acción a partir de 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 indicarle a la casilla de verificación que ha terminado de editar cuando se hace clic en él, en lugar de esperar hasta que el usuario abandona 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(); } }
Editar: un evento de DoubleClick se trata por separado de un evento MouseUp. Si se detecta un evento de DoubleClick, la aplicación ignorará el primer evento MouseUp por completo. Esta lógica debe agregarse al evento CellDoubleClick además del evento MouseUp:
private void myDataGrid_OnCellDoubleClick(object sender,DataGridViewCellEventArgs e) { // End of edition on each click on column of checkbox if (e.ColumnIndex == myCheckBoxColumn.Index && e.RowIndex != -1) { myDataGrid.EndEdit(); } }
fuente
KeyPreview
como verdadero en el formulario y cuandoe.KeyCode == Keys.Space
, configuroe.Handled = true
. En otras palabras, acabo de deshabilitar la edición del teclado.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 activa mientras se completa 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(); } }
fuente
CellContentClick
lugar deCellMouseUp
porque se llamará a la última cuando el usuario haga clic en cualquier lugar dentro de la celda, mientras que a la primera solo se le llamará cuando se haga clic en la casilla de verificación.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..... }
fuente
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); } }
fuente
CommitEdit
desdeCurrentCellDirtyStateChanged
es la solución completa.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 } } }
fuente
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 hace clic en la casilla de verificación para poder usar esta función:
con esto puedes usarlo incluso con un evento diferente.
fuente
He encontrado una respuesta más sencilla a este problema. Simplemente uso lógica inversa. El código está en VB pero no es muy diferente a 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 de esto es que no es necesario realizar varios eventos.
fuente
Lo que funcionó para mí fue
CurrentCellDirtyStateChanged
en combinación condatagridView1.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(); }
fuente
El código se repetirá 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; } } }
fuente
En el caso de CellContentClick, puede utilizar 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; } } }
fuente
Probé algunas respuestas desde aquí, pero siempre he tenido algún tipo de problema (como hacer doble clic o usar el teclado). Entonces, combiné algunos de ellos y obtuve un comportamiento consistente (no es perfecto, pero funciona correctamente).
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. }
fuente
Para hacer esto cuando se usa devexpress xtragrid, es necesario manejar el evento EditValueChanged de un elemento del repositorio correspondiente como se describe aquí . También es importante llamar al método gridView1.PostEditor () para asegurarse de que se haya publicado el valor modificado. 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 utilizar un bucle for para iterar sobre las filas.
fuente
Quitar el foco después de los cambios de valor de celda permite que los valores se actualicen en DataGridView. Elimine el foco estableciendo 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); } }
fuente
Puede forzar a la celda a confirmar el valor tan pronto como haga clic en la casilla de verificación y luego capture el evento CellValueChanged . El CurrentCellDirtyStateChanged incendios tan pronto como haga 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 .
fuente
Ben Voigt encontró la mejor solución en un comentario-respuesta anterior:
private void dgvStandingOrder_CurrentCellDirtyStateChanged(object sender, EventArgs e) { if (dgvStandingOrder.CurrentCell is DataGridViewCheckBoxCell) dgvStandingOrder.CommitEdit(DataGridViewDataErrorContexts.Commit); }
En serio, eso es TODO lo que necesitas.
fuente