Descargar ejemplo LlenarTreeViewASPX.zip
El Control TreeView es un control jerárquico que normalmente se puede llenar desde un archivo XML o de forma manual, pero en ocasiones no se pueden tener los datos en un XML y necesitamos recuperarlos desde la Base de Datos. En este artículo veremos una forma de hacer este trabajo.
Hace poco tuve el siguiente problema, necesitaba crear un menú en un control TreeView para una aplicación web, las opciones del menú varían según el usuario que ingrese al sistema. La idea básica era esa, bien, tener un archivo XML no me servía de nada, las opciones no eran fijas, sino que variaban, si creaba varios archivos XML no los podría controlar si se decide cambiar las opciones puesto que el Admin del sistema podía quitarle opciones a un usuario y mi Servidor Web no me da permiso de escribir archivos, en fin…. el análisis del problema demandaba mucho mas tiempo y más condiciones que solo las nombradas, ¿la solución? llenar el control TreeView directamente desde la Base de Datos.
Empezamos la aplicación creando la siguiente estructura de directorios, tal como muestra la imágen siguiente.
Ahora, lo primero que haremos será crear la Clase que invocará al Stored Procedure desde la Base de Datos. Crearemos una Clase (obviamente en la carpeta App_Code y si no hubiera, creamos esta carpeta primero) llamada Usuario_DAL (el sufijo DAL es por Data Access Layer) y en esta clase escribiremos el siguiente código:
using System; using System.Data; using System.Configuration; using System.Data.SqlClient; public class Usuario_DAL { private int _idUsuario; public Usuario_DAL(int idUsuario) {_idUsuario = idUsuario;} public DataTable leerOpciones() { SqlConnection cnn = new SqlConnection(ConfigurationManager.ConnectionStrings["miBaseDatos"].ConnectionString); SqlCommand cmd = new SqlCommand("uspListarOpcionesUsuario", cnn); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add("@idUsuario", SqlDbType.Int).Value = _idUsuario; cnn.Open(); DataTable dtt = new DataTable(); dtt.Load(cmd.ExecuteReader(), LoadOption.OverwriteChanges); cnn.Close(); return dtt; } }
Bien, expliquemos el código. El constructor de esta clase recibe un parámetro llamado idUsuario, que debe ser el código del usuario que ingresa al Sistema y que servirá para hacer los filtros en las tablas para conseguir mostrar solo las opciones de cada usuario. El método leerOpciones como se darán cuenta retorna un objeto DataTable. Se ejecuta el Stored procedure que devuelve la consulta que se vió en el gráfico anterior como un SqlDataReader, esto para cortar la conexión con la Base de Datos en cuanto se ejecute esta acción, así liberamos la conexión con la Base de Datos. Este SqlDataReader se puede convertir fácilmente en un objeto DataTable usando el método Load de la instancia del DataTable, el parámetro LoadOption.OverwriteChanges solo indica que se deben sobreescribir los datos si es que hubiesen en el DataTable, como nuestro DataTable (dtt) esta vacío no nos preocupamos por eso. Cerramos la conexión que utilizó nuestro objeto SqlCommand y devolvemos nuestro DataTable.
Ahora, este proceso solo nos ha servido para poder devolver el DataTable, ahora, falta el proceso que carga las opciones en el TreeView y esto lo haremos en otra clase que vamos a crear (en la misma carpeta App_Code) y le llamaremos Usuario_BLL (el sufijo BLL se debe a Bussiness Logic Layer). En dicha clase escribiremos el siguiente código:
using System; using System.Data; using System.Web.UI.WebControls; public class Usuario_BLL { public Usuario_BLL(){} public void cargarOpcionesUsuario(int idUsuario, TreeView tvw) { string grupo = "", modulo = ""; TreeNode nodoG = new TreeNode(); TreeNode nodoM = new TreeNode(); Usuario_DAL user = new Usuario_DAL(idUsuario); DataTable dtt = user.leerOpciones(); for (int i = 0; i < dtt.Rows.Count; i++) { DataRow filaM = dtt.Rows[i]; if (modulo != filaM[1].ToString()) { grupo = filaM[3].ToString(); nodoG = new TreeNode(grupo, filaM[2].ToString()); modulo = filaM[1].ToString(); nodoM = new TreeNode(modulo, filaM[0].ToString()); nodoG.ChildNodes.Add(new TreeNode(filaM[5].ToString(), filaM[4].ToString(), "", filaM[6].ToString(), "_self")); nodoM.ChildNodes.Add(nodoG); tvw.Nodes.Add(nodoM); } else { if (grupo != filaM[3].ToString()) { grupo = filaM[3].ToString(); nodoG = new TreeNode(grupo, filaM[2].ToString()); nodoM.ChildNodes.Add(nodoG); } nodoG.ChildNodes.Add(new TreeNode(filaM[5].ToString(), filaM[4].ToString(), "", filaM[6].ToString(), "_self")); } } dtt.Dispose(); dtt = null; } }
Analicemos. Esta clase no recibe parámetros en su constructor. Posee un único método llamado cargarOpcionesUsuario que recibe dos parámetros, el primero es el código del Usuario por el que haremos el filtro y el segundo es el nombre del control TreeView que llenaremos con las opciones.
Instanciamos un obejto de la clase Usuario_DAL pasandole como dato el id de usuario para que nos devuelva el objeto DataTable que necesitamos para hacer este trabajo.
La lógica para este último paso es bastante sencilla, en realidad se trata de recorrer la tabla e ir agregando las opciones a un nuevo objeto nodo (TreeNode), luego este nodo lo agregaremos como un nodo hijo a un nodo de nivel superior, en este caso el que contendrá los grupos y finalmente este nodo de grupos lo agregaremos a un nodo principal que será el que contenga los módulos. La idea es que por cada cambio en el campo de módulos, agreguemos un nuevo módulo, y por cada cambio en el campo grupos, agreguemos un nuevo grupo, en el caso de las opciones no es necesario hacer esta validación pues cada opción será diferente.
Un objeto TreeNode tiene 5 sobrecargas, yo he utilizado dos de ellas:
* nodoG = new TreeNode(grupo, filaM[2].ToString()); – Esta pide el texto que se mostrará al usuario y el valor que tendrá dicho nodo, en este caso el código del propio grupo.
* nodoG.ChildNodes.Add(new TreeNode(filaM[5].ToString(), filaM[4].ToString(), «», filaM[6].ToString(), «_self»)); – Esta segunda forma ademas, pide una imágen para mostrar, que no hemos considerado, un URL para usarlo como Hipervínculo y en último lugar, la ventana de destino del enlace, que será nuestra propia ventana.
Ahora, en una página web agregamos un control TreeView y escribimos el siguiente código:
protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { Usuario_BLL user = new Usuario_BLL(); user.cargarOpcionesUsuario(1, TreeView1); } }
Obviamente en el Load de la página. el primer parámetro yo lo he considerado como fijo, pero en el caso de Uds. puede ser una variable de Session, o un dato recuperado del URL o de un form, etc. que será el que se envíe para el filtro en la clase de acceso a datos. El resultado final debe ser el que se muestra en esta imagen.
Saludos, hasta el próximo artículo.
Hola,
Tengo un treeview que fue llenado con información de 2 tablas de sql server manager studio mediante codigo. Cabe mencionar que lo anterior fue realizado en Visual Studio WPF Visual Basic en una estructura en Capas. Mi consulta es como puedo extraer la información contenida en el header de un item cuando hago doble click en dicho item. Este es el codigo con que llene el treeView.
Private Sub CargarArbolPresup()
Dim dtM As DataTable
Dim dtP As DataTable
‘llamos a las funciones de la clases repsectiva Capa Entidad y guardamos los datos en varibles datatable
dtM = CNMand.ListadoMandantes
dtP = CNPre.ListadoPresupuestos
‘recorremos todas las filas de nuestra tabla Mandantes
For Each FilaM As DataRow In dtM.Rows
Dim DatosMandante As New TreeViewItem
Dim Panel As New StackPanel
Panel.Orientation = Orientation.Horizontal
Panel.Height = «16»
Dim lbl As New TextBlock
lbl.Height = «12»
lbl.Text = FilaM(«RutMand») + » » + FilaM(«RazSocMand»)
Dim img As New Image
img.Source = New BitmapImage(New Uri(«C:\Users\pcant\source\repos\PreUnit\CapaPresentacion\Imagenes\icons8_archive_folder_16.png»))
Panel.Children.Add(img)
Panel.Children.Add(lbl)
DatosMandante.Header = Panel
NodPre.Items.Add(DatosMandante)
‘recorremos todas las filas de nuestra tabla Presupuesto
For Each FilaP As DataRow In dtP.Rows
Dim DatosPresupuesto As New TreeViewItem
‘Colgamos los presupuestos a sus respectivos mandantes
If FilaP(«RutMand») = FilaM(«RutMand») Then
Dim Panel1 As New StackPanel
Dim img1 As New Image
Dim lbl1 As New TextBlock
Panel1.Orientation = Orientation.Horizontal
Panel1.Height = «16»
lbl1.Height = «12»
‘Cargamos los datos del presupuesto a label
lbl1.Text = FilaP(«CodPre») + » » + FilaP(«DetPre»)
img1.Source = New BitmapImage(New Uri(«C:\Users\pcant\source\repos\PreUnit\CapaPresentacion\Imagenes\building_48px.png»))
img1.Stretch = Stretch.Uniform
‘Cargamos al stackPanel imagen y datos del presupuesto
Panel1.Children.Add(img1)
Panel1.Children.Add(lbl1)
‘Cargamos al Header el StackPanel
DatosPresupuesto.Header = Panel1
DatosMandante.Items.Add(DatosPresupuesto)
End If
Next
‘Expandimos los nodos hijos (Mandante) del TreeView
DatosMandante.IsExpanded = True
Next
End Sub