TreeView: Armar la estructura de árbol usando los datos de dos tablas
Además de mostrar como armar la estructura de árbol tambien se muestra el uso de algunas propiedades del control TreeView (VB.NET – ADO.NET)

Fecha: 30/Abr/2005 (20/04/2005)
Autor: Carlos A. Reyes ([email protected])

 


El siguiente artículo tiene la misión de dar una idea y mostrar una forma de como cargar el control TreeView con datos de dos tablas (que también  podrían ser tres o más tablas, un ejemplo podría ser tener cuatro tablas y usarlo en este orden de jerarquía: Softwares, Marcas, Nombre de Productos, Versiones), y además mostrar como usar algunas de las propiedades, métodos y eventos importantes que posee el propio control.

Algunas características del ejemplo son: armar la estructura del árbol basándose en dos tablas, poder realizar Drag and Drop entre los nodos, agregar imágenes al árbol, habilitar/deshabilitar la edición de las etiquetas de los nodos, habilitar/deshabilitar los CheckBox, modificar en cascada los CheckBox según el estado del nodo padre, listar los nodos de último nivel que están chequeados, habilitar/deshabilitar el Drag and Drop, mostrar el path del nodo seleccionado,  dentro del menú contextual están las opciones para poder agregar un nuevo nodo, agregar un nuevo nodo raíz, eliminar un nodo seleccionado, y también se podrán algunas otras opciones sencillas que se puede realizar con el control.

Para el ejemplo se ha utilizado un Form (Form1), el control TreeView (TreeView1), un menú principal (MainMenu1), un ImageList (ImageList1), que se lo vinculó con la TreeView1 para poder mostrar los nodos con gráficos, un menú de contexto (ContextMenu1) y una Barra de Estado (SB). Para los datos que muestro en el ejemplo me base en las tablas “Region” y “Territories” de la base “Northwind” que trae MSSQL 2000, por las dudas dentro del .zip que acompaña al artículo está el archivo “EjemploBD” con los datos que utilicé, solo que en formato XML.

La forma que uso para explicar el funcionamiento es mostrando todo el código, realizando comentarios en casi todos los renglones.

A continuación sigue código en Visual Basic:

Imports System.Data.SqlClient

Public Class Form1
    Inherits System.Windows.Forms.Form

    ' variable del objeto DataView, se usa para poder realizar filtros dentro de la misma
    Private oVista As DataView
    ' variable (Flag) usada para indicar que si hay o no un Drag and Drop dentro del TreeView
    Private DragDropTreeView As Boolean
    ' variable que guarda el nodo arrastrado por el usuario.
    Private NodoOrigen As TreeNode

#Region " Código generado por el Diseñador de Windows Forms "

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim nodo As TreeNode

        ' crear conexión
        Dim oConexion As New SqlConnection
        oConexion.ConnectionString = "Server=(local);Database=Northwind;uid=sa;pwd=;"

        ' crear los DataAdapter
        Dim oDATerritories As New SqlDataAdapter("SELECT * FROM Territories ORDER BY TerritoryDescription", oConexion)
        Dim oDARegion As New SqlDataAdapter("SELECT * FROM Region ORDER BY RegionDescription", oConexion)

        ' crear conjunto de datos
        Dim oDataSet As New DataSet

        ' abrir la conexión
        oConexion.Open()

        ' utilizar los adaptadores para llenar el dataset con las tabla
        oDATerritories.Fill(oDataSet, "Territories")
        oDARegion.Fill(oDataSet, "Region")

        ' cerrar la conexión
        oConexion.Close()

        ' defino variables del tipo DataTable
        Dim oTablaTerritories As DataTable
        Dim oTablaRegion As DataTable

        ' asigno a las variables los datos de las tablas del DataSet
        oTablaTerritories = oDataSet.Tables("Territories")
        oTablaRegion = oDataSet.Tables("Region")

        ' lleno la vista con el contenido de la Tabla Territories
        oVista = oTablaTerritories.DefaultView

        ' deshabilita la actualización en pantalla del control TreeView 
        TreeView1.BeginUpdate()

        ' defino variable del tipo DataRow
        Dim Registro As DataRow

        ' creo un nodo raiz (el nombre Country, puede ser cualquier texto como Raíz, Root, etc.)
        nodo = TreeView1.Nodes.Add("Country")

        For Each Registro In oTablaRegion.Rows
            ' agrego el nodo en el segundo nivel
            nodo = TreeView1.Nodes(0).Nodes.Add(Trim(Registro("RegionDescription")))
            ' si no hay un nodo raiz, se usaría la siguiente línea
            'nodo = TreeView1.Nodes.Add(Trim(Registro("RegionDescription")))

            ' realizo un filtro dentro de la vista
            oVista.RowFilter = "RegionId = " & Registro("RegionID")

            ' ciclo para recorrer la vista previamente filtrada
            Dim a As Integer
            For a = 0 To oVista.Count - 1
                ' agrego el nodo en el tercer nivel
                nodo.Nodes.Add(Trim(oVista.Item(a).Row("TerritoryDescription")))
            Next
            ' expando todos los nodos de árbol secundario
            nodo.ExpandAll()
        Next
        ' habilita la actualización en pantalla del control TreeView
        TreeView1.EndUpdate()

        ' modifico la propiedad AllowDrop a True para poder realizar Drag and Drop
        TreeView1.AllowDrop = True

        ' modifico la propiedad Sorted a True para que los nodos estén ordenados
        TreeView1.Sorted = True
    End Sub

    Private Sub TreeView_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles TreeView1.MouseDown
        ' pregunto si el botón que estoy pulsando es el izquierdo para poder arrastrar el nodo
        If e.Button.Left = MouseButtons.Left Then
            ' señalo que se está haciendo un Drag and Drop dentro del TreeView
            DragDropTreeView = True

            ' obtengo el arbol del control TreeView1
            Dim tree As TreeView = CType(sender, TreeView)

            ' recupero el nodo debajo del mouse.
            Dim node As TreeNode
            node = tree.GetNodeAt(e.X, e.Y)

            ' establezco el nodo del árbol seleccionado actualmente en el control TreeView
            tree.SelectedNode = node

            ' guardo los datos del origen del nodo
            NodoOrigen = CType(node, TreeNode)

            ' inicio la operación Drag and Drop con una copia clonada del nodo.
            If Not node Is Nothing Then
                tree.DoDragDrop(node.Clone(), DragDropEffects.Copy)
            End If
        End If
    End Sub

    Private Sub TreeView_DragDrop(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TreeView1.DragDrop
        If DragDropTreeView = True Then
            ' determino si los datos almacenados en la instancia están asociados al formato especificado del TreeView
            If e.Data.GetDataPresent("System.Windows.Forms.TreeNode", False) Then
                ' variable que sirve para guardar el valor de un punto en coordenadas X e Y
                Dim pt As Point
                ' variable que sirve para guardar el valor del nodo de destino
                Dim DestinationNode As TreeNode

                ' uso PointToClient para calcular la ubicación del mouse sobre el control TreeView
                pt = CType(sender, TreeView).PointToClient(New Point(e.X, e.Y))
                ' uso este punto para recuperar el nodo de destino dentro del árbol del control TreeView.
                DestinationNode = CType(sender, TreeView).GetNodeAt(pt)
                ' verifico que el nodo de destino sea distinto al nodo de origen
                If DestinationNode.FullPath <> NodoOrigen.FullPath Then
                    DestinationNode.Nodes.Add(CType(NodoOrigen.Clone, TreeNode))
                    ' expando el nodo padre donde agregue el nuevo nodo. Sin esto, solo aparecería el signo +.
                    DestinationNode.Expand()
                    ' elimino el nodo de origen dentro del árbol
                    NodoOrigen.Remove()
                End If
            End If
        End If
    End Sub

    Private Sub TreeView_DragOver(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TreeView1.DragOver
        ' Verifica si dentro del TreeView se está arrastrando
        If DragDropTreeView Then
            ' deshabilita la actualización en pantalla del control TreeView 
            TreeView1.BeginUpdate()

            ' obtengo el árbol
            Dim tree As TreeView = CType(sender, TreeView)

            ' establezco el efecto de la operación Drag and Drop
            e.Effect = DragDropEffects.None

            ' pregunto por si el formato es válido?
            If Not e.Data.GetData(GetType(TreeNode)) Is Nothing Then

                ' Obtengo el punto en la pantalla.
                Dim pt As New Point(e.X, e.Y)

                ' Convierto a un punto en el sistema de coordenadas del control TreeView
                pt = tree.PointToClient(pt)

                ' pregunto si el mouse está sobre un nodo válido
                Dim node As TreeNode = tree.GetNodeAt(pt)
                If Not node Is Nothing Then
                    ' establezco el efecto de la operación Drag and Drop
                    e.Effect = DragDropEffects.Copy
                    ' establezco el nodo del árbol seleccionado actualmente en el control TreeView
                    tree.SelectedNode = node
                End If

            End If
            ' habilita la actualización en pantalla del control TreeView
            TreeView1.EndUpdate()
        End If
    End Sub

    Private Sub TreeView1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles TreeView1.MouseUp
        ' señalo que no está haciendo un Drag and Drop dentro del TreeView
        DragDropTreeView = False
    End Sub

    Private Sub TreeView1_BeforeExpand(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewCancelEventArgs) Handles TreeView1.BeforeExpand
        ' le asigno la imagen con la carpeta abierta
        TreeView1.SelectedImageIndex = 1
    End Sub

    Private Sub MenuItem2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuSalir.Click
        ' salgo del formulario
        Me.Close()
    End Sub

    Private Sub mnuLabel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuLabel.Click
        If mnuLabel.Checked = True Then
            ' quito el check del menú
            mnuLabel.Checked = False
            ' configuro la propiedad LabelEdit, para que no pueda editar las etiquetas de los nodos
            TreeView1.LabelEdit = False
        Else
            ' coloco el check del menú
            mnuLabel.Checked = True
            ' configuro la propiedad LabelEdit, para que pueda editar las etiquetas de los nodos
            TreeView1.LabelEdit = True
        End If
    End Sub

    Private Sub mnuHotTracking_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuHotTracking.Click
        If mnuHotTracking.Checked = True Then
            ' quito el check del menú
            mnuHotTracking.Checked = False
            ' configuro la propiedad HotTracking, para que no aparezcan un link las etiquetas de los nodos 
            TreeView1.HotTracking = False
        Else
            ' coloco el check del menú
            mnuHotTracking.Checked = True
            ' configuro la propiedad HotTracking, para que parezcan un link las etiquetas de los nodos 
            TreeView1.HotTracking = True
        End If
    End Sub

    Private Sub mnuCheckBox_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuCheckBox.Click
        If mnuCheckBox.Checked = True Then
            ' deshabilito el menu para listar los nodos de último nivel chequeados
            mnuListaCheck.Visible = False
            ' quito el check del menú
            mnuCheckBox.Checked = False
            ' configuro la propiedad CheckBoxes, para que no aparezcan los checkbox en los nodos
            TreeView1.CheckBoxes = False
        Else
            ' habilito el menu para listar los nodos de último nivel chequeados
            mnuListaCheck.Visible = True
            ' coloco el check del menú
            mnuCheckBox.Checked = True
            ' configuro la propiedad CheckBoxes, para que aparezcan los checkbox en los nodos
            TreeView1.CheckBoxes = True
        End If
    End Sub

    Private Sub mnuAllowDrop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuAllowDrop.Click
        If mnuAllowDrop.Checked = True Then
            ' quito el check del menú
            mnuAllowDrop.Checked = False
            ' configuro la propiedad AllowDrop, para que no pueda realizar un Drag and Drop de los nodos
            TreeView1.AllowDrop = False
        Else
            ' coloco el check del menú
            mnuAllowDrop.Checked = True
            ' configuro la propiedad AllowDrop, para que pueda realizar un Drag and Drop de los nodos
            TreeView1.AllowDrop = True
        End If
    End Sub

    Private Sub mnuPath_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuPath.Click
        If mnuPath.Checked = True Then
            ' quito el check del menú
            mnuPath.Checked = False
            ' hago invisible la Barra de estado donde muestro el path del nodo seleccionado
            SB.Visible = False
        Else
            ' coloco el check del menú
            mnuPath.Checked = True
            ' hago visible la Barra de estado donde muestro el path del nodo seleccionado
            SB.Visible = True
        End If
    End Sub

    Private Sub mnuFullRowSelect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuFullRowSelect.Click
        If mnuFullRowSelect.Checked = True Then
            ' quito el check del menú
            mnuFullRowSelect.Checked = False
            ' configuro la propiedad FullRowSelect, para que no mostrar la selección a todo el ancho del TreeView
            TreeView1.FullRowSelect = False
            ' configuro la propiedad ShowLines, para que muestre las líneas del árbol
            TreeView1.ShowLines = True
        Else
            ' coloco el check del menú
            mnuFullRowSelect.Checked = True
            ' configuro la propiedad FullRowSelect, para mostrar la selección a todo el ancho del TreeView
            TreeView1.FullRowSelect = True
            ' configuro la propiedad ShowLines, para que no muestre las líneas del árbol,
            ' si no se hiciera esto la propiedad FullRowSelect no tendría efecto
            TreeView1.ShowLines = False
        End If
    End Sub

    Private Sub TreeView1_AfterCheck(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles TreeView1.AfterCheck
        ' deshabilita la actualización en pantalla del control TreeView 
        TreeView1.BeginUpdate()
        ' llamo a la Sub donde realizo los check
        ActualizarCheck(e.Node, e.Node.Checked)
        ' habilita la actualización en pantalla del control TreeView
        TreeView1.EndUpdate()
    End Sub

    Private Sub ActualizarCheck(ByVal node As TreeNode, ByVal check As Boolean)
        ' actualizo los check de los nodos hijos, del nodo que se envío como parametro y a con el valor de parametro
        Dim n As TreeNode
        For Each n In node.Nodes
            n.Checked = check
            If n.Nodes.Count <> 0 Then
                ActualizarCheck(n, check)
            End If
        Next n
    End Sub

    Private Sub TreeView1_AfterSelect(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles TreeView1.AfterSelect
        ' recupero el Path donde está la selección y lo pongo en la barra de estado
        SB1.Text = e.Node.FullPath
    End Sub

    Private Sub mnuAgregarRaiz_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuAgregarRaiz.Click
        ' agrego un nodo al nivel de la raíz
        TreeView1.Nodes.Add("Nuevo Nodo Raíz")
    End Sub

    Private Sub mnuAgregarSecundario_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuAgregarSecundario.Click
        ' pregunto si hay un nodo seleccionado
        If IsNothing(TreeView1.SelectedNode) = False Then
            ' agrego un nuevo nodo secundario dentro del nodo seleccionado
            TreeView1.SelectedNode.Nodes.Add("Nuevo Nodo Secundario")
        Else
            MessageBox.Show("No hay un nodo seleccionado para agregar uno nuevo.", "Agregar nodo secundario", MessageBoxButtons.OK, MessageBoxIcon.Information)
        End If
    End Sub

    Private Sub mnuEliminar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuEliminar.Click
        ' pregunto si hay un nodo seleccionado
        If IsNothing(TreeView1.SelectedNode) = False Then
            ' elimino el nodo seleccionado
            TreeView1.SelectedNode.Remove()
        Else
            MessageBox.Show("No hay un nodo seleccionado para eliminar.", "Eliminar nodo", MessageBoxButtons.OK, MessageBoxIcon.Information)
        End If
    End Sub

    Private Sub mnuClear_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuClear.Click
        ' elimino todos los nodos del control TreeView
        TreeView1.Nodes.Clear()
    End Sub

    Private Sub mnuListaCheck_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuListaCheck.Click
        Dim NombresNodo As New ArrayList
        Dim Nodo As TreeNode

        ' llamado a la SUB para buscar los nodos de último nivel chequeados
        For Each Nodo In TreeView1.Nodes
            ObtenerNodosChequeados(Nodo, NombresNodo)
        Next

        ' proceso para concatenar y mostrar todos los nombre de los nodos de último nivel chqueados
        Dim a As Integer
        Dim str As String
        For a = 0 To NombresNodo.Count - 1
            str = str & NombresNodo.Item(a) & Microsoft.VisualBasic.vbCrLf
        Next

        MessageBox.Show(str)
    End Sub

    Private Sub ObtenerNodosChequeados(ByVal nodo As TreeNode, ByVal NombreNodo As ArrayList)
        ' pregunto si el nodo es un nodo de último nivel
        If nodo.Nodes.Count = 0 Then
            ' pregunto si el nodo esta checkeado
            If nodo.Checked Then
                ' Obtengo el Path y lo agrego al ArrayList
                NombreNodo.Add(nodo.FullPath)
            End If
        Else
            ' este no es un nodo de último nivel
            Dim n As TreeNode
            For Each n In nodo.Nodes
                ObtenerNodosChequeados(n, NombreNodo)
            Next n
        End If
    End Sub

    Private Sub TreeView1_BeforeLabelEdit(ByVal sender As Object, ByVal e As System.Windows.Forms.NodeLabelEditEventArgs) Handles TreeView1.BeforeLabelEdit
        ' aca se debería poner todo el código necesario para validar los caracteres
        ' ingresados dentro de la etiqueta cuando se modifica la misma.
    End Sub

    Private Sub mnuExpandir_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuExpandir.Click
        ' expando todos los nodos del control TreeView
        TreeView1.ExpandAll()
    End Sub

    Private Sub mnuContraer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuContraer.Click
        ' contraer todos los nodos del control TreeView
        TreeView1.CollapseAll()
    End Sub
End Class

 


Espero que el artículo les haya sido útil, si es así por favor colabora conmigo votando por este artículo en PanoramaBox. Gracias.


 


Fichero con el código de ejemplo: creyes_EjemploTreeView.zip - 14,5 KB


ir al índice