TreeView: Armar la estructura de árbol usando los datos de dos tablas Fecha: 30/Abr/2005 (20/04/2005)
|
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