jueves, 17 de mayo de 2012

[Winforms] TreeView– Cambiar Estado Node con CheckBox

 

Introducción

Muchas veces es necesario cambiar el estado de ítems predecesores o hijo según ciertos criterios, el control TreeView por posee una estructura jerárquica en sus datos es un caso de esta situación.

 

Validar estado de los nodos


En la implementación de código que se puede observar aplica conceptos simples como de validación de estados de los nodos del treeview.

Básicamente consiste en dos parte

  •    validar si el nodo tiene un nodo padre, para lo cual será necesario verificar si todos los hijos están marcados
  •    cambiar el estado a todos los hijos según la marca de este nodo

Estas acciones se realizan sobre el mismo evento ya que implica de forma contextual al nodo que interviene en la acción

 

private void tvCategoryproducts_AfterCheck(object sender, TreeViewEventArgs e)
{
    //
    // Se remueve el evento para evitar que se ejecute nuevamente por accion de cambio de estado 
    // en esta operacion
    //
    tvCategoryproducts.AfterCheck -= tvCategoryproducts_AfterCheck;

    //
    // Se valida si el nodo marcado tiene presedente
    // en caso de tenerlo se debe evaluar los nodos al mismo nivel para determinar si todos estan marcados, 
    // si lo estan se marca tambien el nodo padre
    //
    if (e.Node.Parent != null)
    {
        bool result = true;
        foreach (TreeNode node in e.Node.Parent.Nodes)
        {
            if (!node.Checked)
            {
                result = false;
                break;
            }
        }

        e.Node.Parent.Checked = result;

    }

    //
    // Se valida si el nodo tiene hijos
    // si los tiene se recorren y asignan el estado del nodo que se esta evaluando
    //
    if (e.Node.Nodes.Count > 0)
    {
        foreach (TreeNode node in e.Node.Nodes)
        {
            node.Checked = e.Node.Checked;
        }
    }


    tvCategoryproducts.AfterCheck += tvCategoryproducts_AfterCheck;

}

 

Optimización usando Linq

Linq nos puede evitar tener que escribir un montón de código, sino lo creen solo basta con dar una mirada a la implementación alternativa que evalúa los nodos marcados

En este caso hice uso de los método de extensión ayudado con lambda, pero se podría haber usado la notación linq sin problemas

 

private void tvCategoryproducts_AfterCheck_UsingLinq(object sender, TreeViewEventArgs e)
{
    //
    // Se remueve el evento para evitar que se ejecute nuevamente por accion de cambio de estado 
    // en esta operacion
    //
    tvCategoryproducts.AfterCheck -= tvCategoryproducts_AfterCheck_UsingLinq;

    //
    // Se valida si el nodo marcado tiene presedente
    // en caso de tenerlo se debe evaluar los nodos al mismo nivel para determinar si todos estan marcados, 
    // si lo estan se marca tambien el nodo padre
    //
    if (e.Node.Parent != null)
    {
        e.Node.Parent.Checked = !e.Node.Parent.Nodes.Cast<TreeNode>().Any(x => !x.Checked);
    }

    //
    // Se valida si el nodo tiene hijos
    // si los tiene se recorren y asignan el estado del nodo que se esta evaluando
    //
    if (e.Node.Nodes.Count > 0)
    {
        e.Node.Nodes.Cast<TreeNode>().ToList().ForEach(x => x.Checked = e.Node.Checked);
    }


    tvCategoryproducts.AfterCheck += tvCategoryproducts_AfterCheck_UsingLinq;

}

Código


Se utilizo Visual Studio 2010 y Sql Compect 3.5

  [C# SkyDrive]

18 comentarios:

  1. Leandro necesito tu ayuda respecto a un crystal que quiero hacer, veras he hecho un datase con el diseñador, este tiene un datatable y 3 campos, lo que quiero es volcar la info de un datagrid a este dataset para usarlo en un crystal report perono se como mandarle la info del datagrdiview al dataset todo esto en vb.net gracias

    ResponderEliminar
  2. hola MIND CORRUPTER

    pero me pregunto que tiene que ver esta pregunta del treeview con crystal, dataset y datagridview ?

    ademas hay un articulo sobre este tema

    [Crystal Reports] - Exportar DataGridView a Crystal

    saludos

    ResponderEliminar
  3. Hola leandro me podrias colaborar, necesito guardar algunos archivos planos con SaveFileDialog en vb.net, pero seria que saliera el form pero sin que me pida el nombre del archivo, ya que ese nombre lo esta quemado en la clase y no cambia porque se utiliza como referencia en otra clase. te agradeseria en lo que me puedas ayudar.

    ResponderEliminar
  4. hola Andres

    no has probado usar el

    FolderBrowserDialog

    para poder seleccionar una carpeta

    saludos

    ResponderEliminar
  5. Hola Leandro de nuevo con problemas, pues te comento tengo un # de combobox´s y pues a la hora de correr el form estos me aparecen con un valor seleccionado automaticamente, algunos dependen de la seleccion de otrso para alimentarse pero no logro evitar este comprotamiento, en el load del form les pongo inicializar con combobox1.text=["Elija Opcion"] pero no sale eso siempre se autoseleccionan......gracias

    ResponderEliminar
  6. hola MIND CORRUPTER

    no has evaluado este articulo

    ComboBox - DropDownList – Opción "Todos"

    recuerda que debes usar el SelectedValue para seleccionar el item, no el Text

    saludos

    ResponderEliminar
  7. hola Leandro..... me podrías ayudar.. necesito este mismo ejemplo, pero yo trabajo con asp.net (web).... te lo agradecería mucho.. Este ejemplo esta buenísimo, GRACIAS!!!

    ResponderEliminar
  8. hola

    el ejemplo seria muy parecido solo que usarias otro evento, el

    TreeNodeCheckChanged

    es mas si analizas el argumento de ese evento veras que tieness la info del nodo para saber cual se puso y analizar el parent y lo hijos aplicando la misma logica aqui descripta

    TreeNodeEventArgs Class

    saludos

    ResponderEliminar
  9. Leandro, como estas? mira lo que estoy buscando y no logro encontrar y si lo encontre no me doy cuenta como adaptarlo. Tengo un treeview cargado desde una tabla donde tengo Los Menu de un form y los Formularios por cada opcion del menu. Ahora bien, cuando elijo un usuario que tiene ciertos formularios habilitados necesito marcar en el treeview aquellos que correspondan.
    la tabla es IdMenu, IdForm,IdUsuario, ahi se carga solo lo que tiene habilitado.

    Atte.

    ResponderEliminar
  10. hola Marco

    pero en ese caso vas a tener que recorrer de forma recursiva el treeview para ir buscando asl coincidencias con los items que hay que marcar segun esos tres datos que defines

    quizas si hay una estructura en arbol primero localizar el primer nivel de nodos para ver que menu se debe trabjar, luego si alguno coincide se busca dentro de este el idform si esta se marca

    lo del idusuario imagino aplica en el filtro de la persona seleccionada y no influye en el treeview porque se filtro previamente

    saludos

    ResponderEliminar
  11. buenas tardes leandro, como hago lo siguiente

    validar las 4 columnas de un gridview que esta en c# y webform con los siguientes criterios

    1.- que la columna 1 no permita vacios y que no acepte menos de 16 digitos y mas de 18

    2.- que la columna 2 no este vacia y que cumpla con un criterio

    actualmente lo que se tiene es que se lee un excel y se cargan los datos a un gridview.

    pregunta como hago para validar que se cumplan con los criterios del usuario y ademas que genere un archivo excel que genere los registros que no cumplieron con alguna validacion.

    mi correo es cora.ben@gmail.com

    ResponderEliminar
  12. espero tu respuesta al comentario de la validacion de datos a gridview o a un excel por medio del datatable que lo contiene

    ResponderEliminar
  13. hola

    la edicion la realizas directo en el propio GridView, pones a editar la fila del grid

    lo pregunto porque podrias usar los controles de validacion de asp.net

    en la toolbox encontraras controels como ser RequiredFieldValidator, RangeValidator, que podrias poner en el ItemTemplate de edicion del gridview


    Validate Controls Inside GridView


    saludos

    ResponderEliminar
  14. hola amigo ayúdame como Guardar el estado de los checkbox de un Treeview en una base de datos y luego recuperarlo su estado en vb.net gracia espero tu respuesta Juan Alex Flores Salas

    ResponderEliminar
  15. hola Juan

    el treeview representa los datos de forma jerarquica, no veo como quieres volcar la seleccion al una tabla, quizas sea mejor usas otra estructura como ser un combo y dos listas para asignar a un item padre que hijos tendria asignado y y asi armar la estructura de arbol

    ademas ni siquiera mencionas que base de datos usas

    saludos

    ResponderEliminar
  16. Hola una pregunta para mantener check al "papa" sin que todos los children esten seleccionados, en orden abajo -arriba.

    Suponga que tiene un áborl asi:

    -- [] ROOT
    -- [] NODE 1
    - [] NODE 1.1
    - [] NODE 1.2
    -- [] NODE 2
    - [] NODE 2.1
    - [] NODE 2.2
    - [] NODE 2.3
    - [] NODE 2.4

    En orden arriba abajo, osea de
    ROOT a NODE 2.4 esta bien pues el root hace que se seleccione todos.

    Ahora de abajo a arriba bien
    (NODE 2.4 a ROOT) per solo si se selecciona unicamnete uno por uno.

    AHora el problema es:
    si selecciono NODE 2.4 por ""jeraquia"" selecciona NODE 2, NODE1 Y ROOT. Pero si selecciono NODE 2.4, DESPUES NODE 2.2 O CUALQUIER OTRO Y DESPUES DE SELECCIONARLO LO VUELVO A DESSELECCIONAR, ME deseelecciona tambien los padres, aunque NODE 2.4 ESTE AUN seleccionado.

    ResponderEliminar
  17. Hola leandro, yo quiero limpiar la seleccion de un treeview.. Gracias

    ResponderEliminar
  18. Hola Leandro. Necesito llenar un TreeView desde un txt con este formato:

    Cordoba*Villa Maria*Barrio Lamadrid
    Cordoba*Villa Maria*Barrio Ameghino
    Cordoba*Villa Maria*Barrio Centro
    Cordoba*Villa Maria*Barrio Palermo
    Cordoba*Villa Nueva*Barrio La Reserva
    Cordoba*Tio Pujio
    Cordoba*James Craik*Barrio JC 1
    Cordoba*James Craik*Barrio JC 2
    Cordoba*Oliva
    Santa Fe*Rosario*Barrio Celedonio Escalada
    Santa Fe*Rosario*Primero de Mayo
    Santa Fe*Rosario*Alberdi
    Santa Fe*Rafaela
    San Luis*Merlo
    Chubut*Trelew
    Chubut*Rawson
    Rio Negro*Bariloche


    Espero que puedas ayudarme. Saludos.

    ResponderEliminar