none
Datagridview, checkbox y botón RRS feed

  • Pregunta

  • Hola!

    Estoy intentando lo siguiente: necesito que se me habilite o deshabilite un botón de un formulario. Esto dependerá del datagrid. Tengo una columna con checkbox, si uno solo está seleccionado, debería habilitarse el botón, sino deshabilitarlo.

    Lo que he intentado me habilitó el botón pero recién al escoger el segundo checkbox y al desmarcar uno ya me deshabilitaba el botón.

    He visto que Leandro sugirió la utilización de java, pero necesito sea todo en C# ya que es un trabajo para la facu.

    GRACIAS!!!

    Lucho :-)

    martes, 16 de enero de 2018 17:16

Respuestas

  • Llamemosle checkBox_All a tu checkbox recientemente agregado en la cabecera. Notemos los siguientes puntos:

    (1)Al marcar checkBox_All, llama a una función que establece el Value de cada checkBox en True o False dependiendo.
    (2)Cada checkBox interno, al cambiar su propiedad, ejecuta el código en el evento dataGridView1_CellValueChanged. Aquí mismo se debe poner que si están todos tildados ó ninguno...cambiar la propiedad Value de checkBox_All.

    Entonces tenemos un problema: al tildar checkBox_All se va a ejecutar (1)...que a su vez dentro de (1) se ejecuta el evento (2)...y el evento (2) ejecuta (1) si todos han sido marcados ó desmarcados...luego, cuando se ejecuta (1) se cambian las propiedades de los checkBox internos...entonces se ejecuta (2)...en fin. Ocurre un stack overflow, o al menos la solución que propongo la construí de esa manera y me topé con ese error.

    La solución es:
    --->Funciones modularizadas:

    private bool checkBox_checked(DataGridViewRow r, int colIndex)
    {
        return r.Cells[colIndex].Value != null && (bool)r.Cells[colIndex].Value;
    }
    private void check_all(bool value)
    {
        int colIndex = 0;
        foreach (DataGridViewRow row in dataGridView1.Rows)
            row.Cells[colIndex].Value = value;
    }

    --->Eventos en juego:

    private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e) { if(dataGridView1.Columns[e.ColumnIndex].Name == "checkBoxColumn") { bool any_checked = dataGridView1.Rows.Cast<DataGridViewRow>().Any(r => checkBox_checked(r, e.ColumnIndex)); bool all_checked = dataGridView1.Rows.Cast<DataGridViewRow>().All(r => checkBox_checked(r, e.ColumnIndex)); button1.Enabled = any_checked; checkBox_All.CheckedChanged -= this.checkBox_All_CheckedChanged; checkBox_All.Checked = all_checked; checkBox_All.CheckedChanged += this.checkBox_All_CheckedChanged; } } private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e) { if (dataGridView1.IsCurrentCellDirty) { dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit); } } private void checkBox_All_CheckedChanged(object sender, EventArgs e) { dataGridView1.CellValueChanged -= this.dataGridView1_CellValueChanged; check_all(checkBox_All.Checked); dataGridView1.CellValueChanged += this.dataGridView1_CellValueChanged;

    button1.Enabled = checkBox_All.Checked;
    }


    Para evitar el problema que puse anteriormente, quitamos el evento asociado(con -=this.bla), ejecutamos la acción que queremos, y lo agregamos de nuevo al evento(con += this...bla).

    miércoles, 17 de enero de 2018 7:10
  • Hola de nuevo, intenté esto y puede ser una solución alternativa a la de leandro:

    private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
    {
        if(dataGridView1.Columns[e.ColumnIndex].Name == "checkBoxColumn")
            button1.Enabled = !dataGridView1.Rows.Cast<DataGridViewRow>().All(r =>
                                                                             (r.Cells[e.ColumnIndex].Value == null || !(bool)r.Cells[e.ColumnIndex].Value));
    }
    
    private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
    {
        if (dataGridView1.IsCurrentCellDirty)
        {
            dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
        }
    }
    La linea de habilitar el botón se fija si alguno está checkeado, pero lo hago al revés, chequeando que todos esten null ó si no estan null, no estén chequeados(esto porque al iniciar el dataGridView, todos los checkbox estan con propiedad Value como null).
    Entonces si hay alguno con Value=true, la consulta "All" no se va a cumplir y el boton se va a habilitar.

    Funciona también de la siguiente forma:
    private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
    {
        if(dataGridView1.Columns[e.ColumnIndex].Name == "checkBoxColumn")
            button1.Enabled = dataGridView1.Rows.Cast<DataGridViewRow>().Any(r =>
                                                                                (r.Cells[e.ColumnIndex].Value != null && (bool)r.Cells[e.ColumnIndex].Value));
    }
    
    private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
    {
        if (dataGridView1.IsCurrentCellDirty)
        {
            dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
        }
    }
    Es mas entendible esta ultima forma ya que si alguno(Any) está chequeado, se habilita el botón.



    martes, 16 de enero de 2018 20:12

Todas las respuestas

  • Hola

    ¿Cómo lo estás trabajando?, al parecer es solo una línea de validación, ya que si has conseguido parte del objetivo, probablemente no este refrescando las peticiones del control. Por otro lado, ¿java? imagino que es javascript; sin embargo, al mencionar el control Datagridview es posible que estés utilizando WindowsForm, y pues no, aquí no existe el javascript, solo en Web.

    Si nos muestras el código que utilizas, podemos darte una mano con tu problema.

    Saludos


    Brayan De la Cruz
    Lima - Perú

    martes, 16 de enero de 2018 17:28
  • Gracias por responder!!!

    Con este código me activa el boton con solo seleccionar un checkbox, pero si desactivo todos, continua el boton disponible...

    private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
            {            
                if (dataGridView1.IsCurrentCellDirty)
                {
                    dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
                }
            }

            private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
            {
                btnConfirmar.Enabled = true;
            }

    Saludos!!!

    martes, 16 de enero de 2018 18:34
  • Quiero ver si entendi bien:

    tenes muchos checkbox, y cuando AL MENOS un checkbox esté chequeado, entonces habilitas el botón...y si todos estan sin chequear, deshabilitas el boton?
    martes, 16 de enero de 2018 19:11
  • Exacto!!! :-)

    Los checkbox están un datagridview!!!

    martes, 16 de enero de 2018 19:20
  • hola

    >>Tengo una columna con checkbox, si uno solo está seleccionado, debería habilitarse el botón, sino deshabilitarlo.

    [DataGridView] – Uso del CheckBox - DataGridView

    podrias usar el evento de la celda para detectar el cambio en el checkbox y alli habilitar o no el boton

    >>He visto que Leandro sugirió la utilización de java, pero necesito sea todo en C#

    java? te refieres a javascript, pero eso solo aplica si es un desarrolo web

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    martes, 16 de enero de 2018 19:39
  • Hola Leandro!!!

    He leído mucho de tus publicaciones, no dudo sea de web lo de java... ya estoy como mareado jajajajaja

    GRACIAS ETERNAS!!!

    Pruebo lo que publicaste y te comento.

    martes, 16 de enero de 2018 19:43
  • Intentando, pero me tira error en donde resalto en negrita junto a los error CS0029 y CS1061:

    private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
            {
                if (e.RowIndex == -1)
                    return;
                if (dataGridView1.Columns[e.ColumnIndex].Name=="SELECCIONAR")
                {
                    DataGridView row = dataGridView1.Rows[e.RowIndex];
                    DataGridViewCheckBoxCell cellselecion = row.Cells["SELECCIONAR"] as DataGridViewCheckBoxCell;
                    if (Convert.ToBoolean(cellselecion.Value))
                    {
                        btnConfirmar.Enabled = true;
                    }
                    else
                    {
                        btnConfirmar.Enabled = false;
                    }              
                }
            }

    martes, 16 de enero de 2018 19:57
  • Hola de nuevo, intenté esto y puede ser una solución alternativa a la de leandro:

    private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
    {
        if(dataGridView1.Columns[e.ColumnIndex].Name == "checkBoxColumn")
            button1.Enabled = !dataGridView1.Rows.Cast<DataGridViewRow>().All(r =>
                                                                             (r.Cells[e.ColumnIndex].Value == null || !(bool)r.Cells[e.ColumnIndex].Value));
    }
    
    private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
    {
        if (dataGridView1.IsCurrentCellDirty)
        {
            dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
        }
    }
    La linea de habilitar el botón se fija si alguno está checkeado, pero lo hago al revés, chequeando que todos esten null ó si no estan null, no estén chequeados(esto porque al iniciar el dataGridView, todos los checkbox estan con propiedad Value como null).
    Entonces si hay alguno con Value=true, la consulta "All" no se va a cumplir y el boton se va a habilitar.

    Funciona también de la siguiente forma:
    private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
    {
        if(dataGridView1.Columns[e.ColumnIndex].Name == "checkBoxColumn")
            button1.Enabled = dataGridView1.Rows.Cast<DataGridViewRow>().Any(r =>
                                                                                (r.Cells[e.ColumnIndex].Value != null && (bool)r.Cells[e.ColumnIndex].Value));
    }
    
    private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
    {
        if (dataGridView1.IsCurrentCellDirty)
        {
            dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
        }
    }
    Es mas entendible esta ultima forma ya que si alguno(Any) está chequeado, se habilita el botón.



    martes, 16 de enero de 2018 20:12
  • Nicolas me ha funcionado a la perfección con la opción nro. 2!!!

    Eternamente agradecido!!!

    Luciano :-)

    ---

    martes, 16 de enero de 2018 22:26
  • Por último, para seguir molestando :-)

    En el mismo datagridview, en la columna de los checkbox, agregué como "encabezado" un checkox. Si el usuario lo tilda, se marcan todos los checkbox y si lo destilda, todos los checkbox quedan desmarcados.

    La consulta es... se puede lograr que ese checkbox del "título" solo quede marcado siempre y cuando TODOS estén seleccionados? Si marco a todos con ese checkbox y luego a uno solo lo desmarco, me sigue apareciendo marcado.

    La idea es que el usuario entienda que si ese checkbox está marcado es porque todos los demás lo están. Sino está marcado es porque o ninguno, o solo algunos, están marcados.

    Gracias

    Luciano :-)

    ---

    martes, 16 de enero de 2018 23:42
  • Llamemosle checkBox_All a tu checkbox recientemente agregado en la cabecera. Notemos los siguientes puntos:

    (1)Al marcar checkBox_All, llama a una función que establece el Value de cada checkBox en True o False dependiendo.
    (2)Cada checkBox interno, al cambiar su propiedad, ejecuta el código en el evento dataGridView1_CellValueChanged. Aquí mismo se debe poner que si están todos tildados ó ninguno...cambiar la propiedad Value de checkBox_All.

    Entonces tenemos un problema: al tildar checkBox_All se va a ejecutar (1)...que a su vez dentro de (1) se ejecuta el evento (2)...y el evento (2) ejecuta (1) si todos han sido marcados ó desmarcados...luego, cuando se ejecuta (1) se cambian las propiedades de los checkBox internos...entonces se ejecuta (2)...en fin. Ocurre un stack overflow, o al menos la solución que propongo la construí de esa manera y me topé con ese error.

    La solución es:
    --->Funciones modularizadas:

    private bool checkBox_checked(DataGridViewRow r, int colIndex)
    {
        return r.Cells[colIndex].Value != null && (bool)r.Cells[colIndex].Value;
    }
    private void check_all(bool value)
    {
        int colIndex = 0;
        foreach (DataGridViewRow row in dataGridView1.Rows)
            row.Cells[colIndex].Value = value;
    }

    --->Eventos en juego:

    private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e) { if(dataGridView1.Columns[e.ColumnIndex].Name == "checkBoxColumn") { bool any_checked = dataGridView1.Rows.Cast<DataGridViewRow>().Any(r => checkBox_checked(r, e.ColumnIndex)); bool all_checked = dataGridView1.Rows.Cast<DataGridViewRow>().All(r => checkBox_checked(r, e.ColumnIndex)); button1.Enabled = any_checked; checkBox_All.CheckedChanged -= this.checkBox_All_CheckedChanged; checkBox_All.Checked = all_checked; checkBox_All.CheckedChanged += this.checkBox_All_CheckedChanged; } } private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e) { if (dataGridView1.IsCurrentCellDirty) { dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit); } } private void checkBox_All_CheckedChanged(object sender, EventArgs e) { dataGridView1.CellValueChanged -= this.dataGridView1_CellValueChanged; check_all(checkBox_All.Checked); dataGridView1.CellValueChanged += this.dataGridView1_CellValueChanged;

    button1.Enabled = checkBox_All.Checked;
    }


    Para evitar el problema que puse anteriormente, quitamos el evento asociado(con -=this.bla), ejecutamos la acción que queremos, y lo agregamos de nuevo al evento(con += this...bla).

    miércoles, 17 de enero de 2018 7:10
  • Hola Nicolas!!!

    Eternamente agradecido. JAMÁS me hubiese salido hacer todo eso a mí. Recién doy los primeros pasos en esto.

    No dudo que a otros estos les servirá también!!!

    GRACIAS!!!

    Luciano :-)

    ---


    miércoles, 17 de enero de 2018 11:46