Foros del Web » Programación para mayores de 30 ;) » .NET »

Construir una lista dinámicamente

Estas en el tema de Construir una lista dinámicamente en el foro de .NET en Foros del Web. Hola a tod@s: Estoy trabajando en un Sitio Web en ASP.NET 2.0 con código C# Quisiera montar la siguiente lista de manera dinámica: FICHEROS MAESTROS ...
  #1 (permalink)  
Antiguo 20/07/2007, 16:00
Avatar de zacktagnan  
Fecha de Ingreso: abril-2005
Mensajes: 501
Antigüedad: 19 años
Puntos: 3
Construir una lista dinámicamente

Hola a tod@s:

Estoy trabajando en un Sitio Web en ASP.NET 2.0 con código C#

Quisiera montar la siguiente lista de manera dinámica:
  • FICHEROS MAESTROS
    • Clientes
    • Ayuntamientos
    • Rutas
    • Municipios
    • Formas de Pago
    • Residuos
    • Vehículos
    • Repartidores
    • Comerciales
    • Empleados
  • ADMINISTRADOR
    • Usuarios
    • Perfiles
    • Menú
  • OPERATIVA
    • Clientes
      • Albarán
      • Pagos a Comerciales
    • Almacenes
      • Albaranes
      • Consultas
    • Ayuntamientos
      • Albaranes
      • Consultas
    • Mancomunidades
      • Albaranes
      • Consultas
    • Repartidores
      • Control
      • Consulta
    • Actividades
      • Generación de Residuos
      • Entregas Valorizador
    • Informes
    • Correspondencia
      • Clientes Pagadores
      • Ayuntamientos
  • MANUAL
  • SALIR

Todos los datos para montar vienen de una tabla [MENU] de la base de datos con esta estructura:
Código:
 CREATE TABLE MENU (mnu_id INT IDENTITY (1,1) NOT NULL,
 mnu_txt NVARCHAR(50) NOT NULL,
 mnu_title NVARCHAR(50) NULL,
 mnu_url NVARCHAR(50) NOT NULL CONSTRAINT DF_menu_mnu_url DEFAULT (('#')),
 mnu_nivel TINYINT NOT NULL,
 mnu_padre_id INT NOT NULL CONSTRAINT DF_menu_mnu_padre_id DEFAULT ((0)),
 mnu_perfiles NVARCHAR(25) NOT NULL,
 CONSTRAINT clave_menu PRIMARY KEY (mnu_id))
La descripción de algunos de los campos de la tabla es la siguiente:
- [mnu_txt] es el texto de la opción.
- [mnu_title] es el texto para la propiedad TITLE de la etiqueta A de vínculo (pues cada opción va vinculada a alguna página).
- [mnrl] es la ruta al vínculo deseado.
- [mnu_nivel] es un número indicador del nivel/subnivel en la que la opción se sitúa en la lista; por ejemplo las opciones como [FICHEROS MAESTROS] están a un nivel 0, una opción por debajo de ésta tendrá el nivel 1, debajo de ésta el nivel 2, etc...
- [mnu_padre_id], es el número para indicar cuál es el nivel padre de cada submenú. Las opciones de primer nivel, es decir nivel 0, no tienen padre y en este caso llevarán un 0 en este campo; los demás si son subniveles de otros llevarán en este campo el ID de los que sean sus padres, por ejemplo, la opción [Clientes] debajo de [Ficheros Maestros] lleva el 1 en este campo.

Como he dicho, quisiera saber como construir la lista deseada a través de los datos de la tabla.

En ASP 3.0 sabría hacerlo más ó menos a través de combinar varias consultas a la vez con varios recordset...
Pero con el ASP.NET 2.0, no llego a ver exactamente la manera, ya que en mi corta experiencia todas las consultas que se construyen se van cargando en controles web como GridView, FormView ó DropDownList.
Y aquí, no veo que sea ese el caso a menos que me equivoque

Si alguien me puede dar alguna pista sobre como construir la consulta, ... si con un objeto SqlDataSource ó con un SqlDataAdapter y DataSet ó con otros, y luego, sobre todo como ir cargando los datos montando el HTML de listas (ul y li) para conseguir la lista planteada.

Al final, esta lista, aplicándole una serie de estilos, se convierte en un menú desplegable.

Espero la(s) respuesta(s) de todo el que me pudiera ayudar...
__________________
Saludos,

zacktagnan.
=================================================

Última edición por zacktagnan; 20/07/2007 a las 16:15
  #2 (permalink)  
Antiguo 21/07/2007, 16:28
Avatar de zacktagnan  
Fecha de Ingreso: abril-2005
Mensajes: 501
Antigüedad: 19 años
Puntos: 3
Re: Construir una lista dinámicamente

Bueno, parece que la solución a lo que planteo puede pasar por utilizar el control Menu de Visual Studio 2005.

He encontrado un ejemplo aquí:
http://www.netveloper.com/contenido2.aspx?IDC=145_0

He bajado el código que está hecho con lenguaje VisualBasic.

La página .aspx lleva el control Menu de la siguiente manera:
Código:
<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Página sin título</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Menu ID="mnuPrincipal" runat="server" BackColor="#B1C3D9" Font-Names="Verdana"
            ForeColor="#336699" Height="20px" MaximumDynamicDisplayLevels="2" Orientation="Horizontal"
            DynamicHorizontalOffset="2" Font-Bold="True" Font-Size="11px" StaticSubMenuIndent=""
            BorderColor="#336699" BorderStyle="Solid" BorderWidth="1px">
            <DynamicMenuStyle BackColor="#B1C3D9" BorderWidth="1px" BorderColor="#336699" Width="180px" />
	        <DynamicMenuItemStyle HorizontalPadding="5px" VerticalPadding="2px" />
	        <DynamicHoverStyle ForeColor="White" Font-Bold="True" BackColor="#336699" />
            <StaticMenuStyle BackColor="#B1C3D9" BorderWidth="1px" BorderColor="#336699" />
	        <StaticMenuItemStyle HorizontalPadding="5px" VerticalPadding="2px" Width="180px" />
	        <StaticHoverStyle ForeColor="White" Font-Bold="True" BackColor="#336699" />
        </asp:Menu>
    </div>
    </form>
</body>
</html>
En la parte .aspx.vb, lleva lo siguiente:
Código:
Imports System.Data
Imports System.Data.SqlClient

Partial Class Default
    Inherits System.Web.UI.Page

    'DEFINIENDO LA CONEXIÓN
    Dim cnDatos As New SqlConnection("server=NOMBRE_SERVIDOR;database=DBApp;uid=sa")

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        If Not Page.IsPostBack Then
            'RECOGIENDO LOS DATOS DE LA BASE DE DATOS
            Dim dtMenuItems As New DataTable
            'INVOCANDO AL PROCEDIMIENTO ALMACENADO
            Dim daMenu As New SqlDataAdapter("ObtenerOpcionesMenu", cnDatos)
            daMenu.SelectCommand.CommandType = CommandType.StoredProcedure
            'LLENANDO EL DataTable
            daMenu.Fill(dtMenuItems)
            'RECORRIENDO EL DataTable PARA AGREGAR LOS ELEMENTOS QUE ESTARÁN EN LA CABECERA DEL MENÚ
            For Each drMenuItem As Data.DataRow In dtMenuItems.Rows
                'ESTA CONDICION INDICA QUE SON ELEMENTOS PADRE
                If (drMenuItem("MenuId").Equals(drMenuItem("PadreId"))) Then
                    Dim mnuMenuItem As New MenuItem
                    mnuMenuItem.Value = drMenuItem("MenuId").ToString
                    mnuMenuItem.Text = drMenuItem("Descripcion").ToString
                    mnuMenuItem.ImageUrl = drMenuItem("Icono").ToString
                    mnuMenuItem.NavigateUrl = drMenuItem("Url").ToString
                    'AGREGANDO EL ITEM [mnuMenuItem] AL MENU [mnuPrincipal]
                    mnuPrincipal.Items.Add(mnuMenuItem)
                    'LLAMANDO AL MÉTODO RECURSIVO ENCARGADO DE GENERAR EL ÁRBOL DEL MENÚ
                    AddMenuItem(mnuMenuItem, dtMenuItems)
                End If
            Next
        End If
    End Sub

    Private Sub AddMenuItem(ByRef mnuMenuItem As MenuItem, ByVal dtMenuItems As Data.DataTable)
        'RECORRIENDO CADA ELEMENTO DEL DataTable PARA PODER DETERMINAR CUÁLES
        'SON ELEMENTOS HIJOS DEL MenuItem DADO PASADO COMO PARÁMETRO ByRef
        For Each drMenuItem As Data.DataRow In dtMenuItems.Rows
            If drMenuItem("PadreId").ToString.Equals(mnuMenuItem.Value) AndAlso _
            Not drMenuItem("MenuId").Equals(drMenuItem("PadreId")) Then
                Dim mnuNewMenuItem As New MenuItem
                mnuNewMenuItem.Value = drMenuItem("MenuId").ToString
                mnuNewMenuItem.Text = drMenuItem("Descripcion").ToString
                mnuNewMenuItem.ImageUrl = drMenuItem("Icono").ToString
                mnuNewMenuItem.NavigateUrl = drMenuItem("Url").ToString
                'AGREGANDO EL NUEVO MenuItem AL MenuItem QUE VIENE DE UN NIVEL SUPERIOR
                mnuMenuItem.ChildItems.Add(mnuNewMenuItem)
                'LLAMADA RECURSIVA PARA VER SI EL NUEVO MenuItem AÚN TIENE ELEMENTOS HIJOS
                AddMenuItem(mnuMenuItem, dtMenuItems)
            End If
        Next
    End Sub
End Class
Por último, la definición de la base de datos, tabla, procedimiento almacenado para cargar los datos:
Código:
create database DBApp;
go
USE DBApp
GO
create table Menu
(
MenuId int identity(1,1) PRIMARY KEY,
Descripcion varchar(20) NOT NULL,
PadreId int NOT NULL,
Posicion int NOT NULL,
Icono varchar(100),
Habilitado bit NOT NULL,
Url varchar(100),
FechaCreacion datetime,
UsuarioCreacion char(10),
FechaModificacion datetime,
UsuarioModificacion char(10)
)
go
CREATE PROCEDURE dbo.ObtenerOpcionesMenu
AS
	SET NOCOUNT ON
	   SELECT MenuId, Descripcion, Posicion, PadreId, Icono, Habilitado, Url
	   FROM dbo.Menu
        WHERE Habilitado = 1

	SET NOCOUNT OFF
go
[*] Con estos datos, solamente habrá niveles superiores, sin subniveles:
Código:
MenuId | Descripcion | PadreId | Posicion |        Icono        | Habilitado | Url | FechaCreacion | UsuarioCreacion | FechaModificacion | UsuarioModificacion
--------------------------------------------------------------------------------------------------------------------------------------------------------------
   1   | INICIO      |    1    |     1    | images/earth2.gif   | True       |  #  | NULL          | NULL            | NULL              | NULL
--------------------------------------------------------------------------------------------------------------------------------------------------------------
   2   | DATOS       |    2    |     1    | images/lock.gif     | True       |  #  | NULL          | NULL            | NULL              | NULL
--------------------------------------------------------------------------------------------------------------------------------------------------------------
   3   | CLIENTES    |    3    |     1    | images/man.gif      | True       |  #  | NULL          | NULL            | NULL              | NULL
--------------------------------------------------------------------------------------------------------------------------------------------------------------
   4   | MANUAL      |    4    |     1    | images/help2.gif    | True       |  #  | NULL          | NULL            | NULL              | NULL
[*] Con estos datos, el registro CLIENTES será subnivel de DATOS, y MANUAL como tiene el campo Habilitado a false no aparecerá (tal como se define en la consulta del procedimiento):
Código:
MenuId | Descripcion | PadreId | Posicion |        Icono        | Habilitado | Url | FechaCreacion | UsuarioCreacion | FechaModificacion | UsuarioModificacion
--------------------------------------------------------------------------------------------------------------------------------------------------------------
   1   | INICIO      |    1    |     1    | images/earth2.gif   | True       |  #  | NULL          | NULL            | NULL              | NULL
--------------------------------------------------------------------------------------------------------------------------------------------------------------
   2   | DATOS       |    2    |     1    | images/lock.gif     | True       |  #  | NULL          | NULL            | NULL              | NULL
--------------------------------------------------------------------------------------------------------------------------------------------------------------
   3   | CLIENTES    |    2    |     1    | images/man.gif      | True       |  #  | NULL          | NULL            | NULL              | NULL
--------------------------------------------------------------------------------------------------------------------------------------------------------------
   4   | MANUAL      |    4    |     1    | images/help2.gif    | False      |  #  | NULL          | NULL            | NULL              | NULL

Tras construir la base de datos con la tabla necesaria e insertar varias filas, lo he probado.

Pasa una cosa, cuánto menos curiosa (igual porque no sé su causa):
- si en la tabla Menu solo hay registros que sean elementos de nivel superior (que no sean hijos ó subniveles de otro nivel ó subnivel), entonces funciona.
- pero a nada que configure uno de los registros como subnivel de otro, entonces me sale una ventana del WebDev.WebServer.exe con este mensaje:

Cita:
WebDev.WebServer.exe ha detectado un problema y debe cerrarse. Sentimos los inconvenientes ocasionados.
Si está en pleno proceso, puede perderse la información que esté trabajando
¿¿Alguien me podría indicar por qué ocurre esto??
¿Hay algún fallo en el código a la hora de construir los submenús ó elmentos hijo, ó en las propiedades de diseño del control Menu empleado?
__________________
Saludos,

zacktagnan.
=================================================
  #3 (permalink)  
Antiguo 22/07/2007, 17:51
Avatar de zacktagnan  
Fecha de Ingreso: abril-2005
Mensajes: 501
Antigüedad: 19 años
Puntos: 3
Re: Construir una lista dinámicamente

¿Ninguna idea aclaratoria...please?
__________________
Saludos,

zacktagnan.
=================================================
  #4 (permalink)  
Antiguo 23/07/2007, 22:00
Avatar de kornissues12  
Fecha de Ingreso: julio-2007
Mensajes: 4
Antigüedad: 16 años, 9 meses
Puntos: 0
Re: Construir una lista dinámicamente

Hola he utilizado algun tiempo C# por lo que tengo una idea de como hacer lo que deceas si es que he entendido bien, lo que deceas es que realices una consulta y con el resultado crees el menu con niveles y subniveles, por ello deseas crear un arreglo dinamico, si es asi puedo ayudarte ya que he utilizado mucho los areglos dinamicos, tal vez estas intrucciones te ayuden

string[] arreglo = new string[1];

Array.Resize(ref arreglo, arreglo.Length + 1);
el primer parametro es la referencia al arreglo y el segundo el nuevo tamaño.

espero te sirva.

Acerca del error al llenado del menu no sabria mucho al respecto ya que es Visual Basic y el lenguaje no es de mi agrado, es posible que error radique que intenta crear un item del menu en la misma posicion y gerarquia de una ya creado por tanto genera una redundancia y/o sobreescritura.
  #5 (permalink)  
Antiguo 24/07/2007, 01:18
Avatar de zacktagnan  
Fecha de Ingreso: abril-2005
Mensajes: 501
Antigüedad: 19 años
Puntos: 3
Re: Construir una lista dinámicamente

Hola kornissues12:

La verdad es que no entiendo muy bien lo que me sugieres...Si me pudieras explicar más detalladamente ...
Es decir, tu el resultado de la consulta ¿¿la metes como new string en el array string arreglo??? No sé, ... igual estoy diciendo una burrada...

Cita:
string[] arreglo = new string[1];

Array.Resize(ref arreglo, arreglo.Length + 1);
el primer parametro es la referencia al arreglo y el segundo el nuevo tamaño.
No obstante, parece que ya he conseguido lo que quería almacenando la consulta en un DataTable y luego recorriendo las Rows y mostrándolas con formato de listas según ciertas condiciones a cumplir a través de if ... else. Y luego a todo le aplico unos estilos Css para que se muestre a modo de menú desplegable.

Lo único que en ciertas partes dónde abro la conexión para cierta consulta no termino de cerrarla pues choca con otra parte abierta ...

Bueno la cosa me queda de esta manera:

El código que transforma todo en menú y los estilos están sacados del código de uno de los menús de la página CSSPLAY, concretamente este:
http://www.cssplay.co.uk/menus/final_drop.html

Tras alguna modificación, la hoja de estilos me queda así
Código:
/*************************************************************************************************/

/* ================================================================ 
This copyright notice must be untouched at all times.

The original version of this stylesheet and the associated (x)html
is available at http://www.cssplay.co.uk/menus/final_drop.html
Copyright (c) 2005-2007 Stu Nicholls. All rights reserved.
This stylesheet and the associated (x)html may be modified in any 
way to fit your requirements.
=================================================================== */

.menu {font-family:Verdana, Arial, Helvetica, sans-serif; width:745px; height:31px; font-size:0.85em; position:relative; z-index:100; border:1px solid #000; border-width:1px 1px 1px 0px; background:#758279;}
/* hack to correct IE5.5 faulty box model */
* html .menu {width:746px; w\idth:745px;}
/* remove all the bullets, borders and padding from the default list styling */
.menu ul {padding:0;margin:0;list-style-type:none;}
.menu ul ul {width:149px;}
/* float the list to make it horizontal and a relative positon so that you can control the dropdown menu positon */
.menu li {float:left;width:149px;position:relative;}
/* style the links for the top level */
.menu a, .menu a:visited {display:block;font-size:11px;text-decoration:none; color:#fff; width:138px; height:31px; border:1px solid #000; border-width:0px 0px 0px 1px; background:#758279; padding-left:10px; line-height:29px;}
/* a hack so that IE5.5 faulty box model is corrected */
* html .menu a, * html .menu a:visited {width:149px; w\idth:138px;}

/* style the second level background */
.menu ul ul a.drop, .menu ul ul a.drop:visited {background:#d4d8bd url(../images/submenu.gif) bottom right no-repeat;}
/* style the second level hover */
.menu ul ul a.drop:hover{background:#c9ba65 url(../images/submenu.gif) bottom right no-repeat;}
.menu ul ul :hover > a.drop {background:#c9ba65 url(../images/submenu.gif) bottom right no-repeat;}
/* style the third level background */
.menu ul ul ul a, .menu ul ul ul a:visited {background:#e2dfa8;}
/* style the third level hover */
.menu ul ul ul a:hover {background:#b2ab9b;}


/* hide the sub levels and give them a positon absolute so that they take up no room */
.menu ul ul {visibility:hidden;position:absolute;height:0;top:31px;left:0; width:149px;border-top:1px solid #000;}
/* another hack for IE5.5 */
* html .menu ul ul {top:30px;t\op:31px;}

/* position the third level flyout menu */
.menu ul ul ul{left:149px; top:-1px; width:149px;}

/* position the third level flyout menu for a left flyout */
.menu ul ul ul.left {left:-149px;}

/* style the table so that it takes no ppart in the layout - required for IE to work */
.menu table {position:absolute; top:0; left:0; border-collapse:collapse;;}

/* style the second level links */
.menu ul ul a, .menu ul ul a:visited {background:#d4d8bd; color:#000; height:auto; line-height:1em; padding:5px 10px; width:128px;border-width:0 1px 1px 1px;}
/* yet another hack for IE5.5 */
* html .menu ul ul a, * html .menu ul ul a:visited {width:150px;w\idth:128px;}

/* style the top level hover */
.menu a:hover, .menu ul ul a:hover{color:#fff; background:#949e7c;}
.menu :hover > a, .menu ul ul :hover > a {color:#fff;background:#949e7c;}

/* make the second level visible when hover on first level list OR link */
.menu ul li:hover ul,
.menu ul a:hover ul{visibility:visible; }
/* keep the third level hidden when you hover on first level list OR link */
.menu ul :hover ul ul{visibility:hidden;}
/* make the third level visible when you hover over second level list OR link */
.menu ul :hover ul :hover ul{ visibility:visible;}
/**/
/* keep the fourth level hidden when you hover on second level list OR link */
.menu ul :hover ul :hover ul ul{visibility:hidden;}
/* make the fourth level visible when you hover over third level list OR link */
.menu ul :hover ul :hover ul :hover ul{ visibility:visible;}

/*************************************************************************************************/
[*] en el .aspx
Código:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Página sin título</title>
    <link href="css/menu_desplegable.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1" runat="server">
    <div class="menu">
        <%= construirMenu()%>
    </div>
    </form>
</body>
</html>
[... SIGUE EN EL SIGUIENTE MENSAJE ...]
__________________
Saludos,

zacktagnan.
=================================================
  #6 (permalink)  
Antiguo 24/07/2007, 01:19
Avatar de zacktagnan  
Fecha de Ingreso: abril-2005
Mensajes: 501
Antigüedad: 19 años
Puntos: 3
Re: Construir una lista dinámicamente

[... VIENE DEL ANTERIOR MENSAJE ...]


[*] en el .aspx.cs
Código:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class Default : System.Web.UI.Page
{
    //ESTABLECIENDO CONEXIÓN
    SqlConnection cnDatos = new SqlConnection("server=NOMBRE_SERVIDOR;database=NOMBRE_BASEdeDATOS;uid=sa;");
    DataTable dtMenuItems = new DataTable();
    string elMenu = "";
    string subMenus = "";
    int total_TOTSubniv = 0;

    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected string construirMenu()
    {
        elMenu = "<ul>";
        //RECOGIENDO LOS DATOS DE LA BASE DE DATOS
        //==========================================
        //INVOCANDO AL PROCEDIMIENTO ALMACENADO
        SqlDataAdapter daMenu = new SqlDataAdapter("ObtenerOpciones_Menu", cnDatos);
        daMenu.SelectCommand.CommandType = CommandType.StoredProcedure;
        //LLENANDO EL DataTable
        daMenu.Fill(dtMenuItems);
        //RECORRIENDO EL DataTable PARA AGREGAR LOS ELEMENTOS QUE ESTARÁN EN LA CABECERA DEL MENÚ
        foreach (DataRow drMenuItem in dtMenuItems.Rows)
        {
            haySubmenus(drMenuItem["mnu_id"].ToString());
            if (total_TOTSubniv > 0)
            {
                //HABIENDO SUBMENÚS
                //ESTA CONDICION INDICA QUE SON ELEMENTOS PADRE
                if (drMenuItem["mnu_id"].ToString() == drMenuItem["mnu_padre_id"].ToString())
                {
                    elMenu = elMenu + "<li><a href=\"" + drMenuItem["mnu_url"].ToString() + "\">" + (drMenuItem["mnu_txt"].ToString()).ToUpper() + "<!--[if IE 7]><!--></a><!--<![endif]--><!--[if lte IE 6]><table><tr><td><![endif]-->";
                    obtenSubmenus(drMenuItem["mnu_id"].ToString());
                    elMenu = elMenu + "<!--[if lte IE 6]></td></tr></table></a><![endif]--></li>";
                }
            }
            else
            {
                //NO HABIENDO SUBMENÚS
                //ESTA CONDICION INDICA QUE SON ELEMENTOS PADRE
                if (drMenuItem["mnu_id"].ToString() == drMenuItem["mnu_padre_id"].ToString())
                {
                    elMenu = elMenu + "<li><a href=\"" + drMenuItem["mnu_url"].ToString() + "\">" + drMenuItem["mnu_txt"].ToString().ToUpper() + "</a></li>";
                }
            }
        }
        elMenu = elMenu + "</ul>";
        return elMenu;
    }

    protected int haySubmenus(string menuId)
    {
        string sql_TOTSubniv = "SELECT COUNT(mnu_id) FROM MENU WHERE mnu_padre_id=" + menuId + " AND mnu_id<>" + menuId + "";
        SqlCommand coman_TOTSubniv = new SqlCommand(sql_TOTSubniv, cnDatos);
        
        try
        {
            cnDatos.Open();
            //RECOGIENDO EL RESULTADO DEL COUNT(mnu_id)
            total_TOTSubniv = int.Parse(coman_TOTSubniv.ExecuteScalar().ToString());
            cnDatos.Close();
        }
        catch (SqlException ex_TOTSubniv)
        {
            Response.Write("Se ha producido un error: " + ex_TOTSubniv);
        }

        return total_TOTSubniv;
    }//FIN DE haySubmenus(...)

    protected string obtenSubmenus(string menuId)
    {
        DataTable dtSubMenus = new DataTable();
        SqlDataAdapter daSubMenus = new SqlDataAdapter("SELECT * FROM MENU WHERE mnu_padre_id=" + menuId + " AND mnu_id<>" + menuId + " ORDER BY mnu_posicion, mnu_txt", cnDatos);
        //LLENANDO EL DataTable
        daSubMenus.Fill(dtSubMenus);
        try
        {
            ////cnDatos.Open();
            elMenu = elMenu + "<ul>";
            foreach (DataRow drSubMenus in dtSubMenus.Rows)
            {
                haySubmenus(drSubMenus["mnu_id"].ToString());
                if (total_TOTSubniv > 0)
                {
                    elMenu = elMenu + "<li><a class=\"drop\" href=\"" + drSubMenus["mnu_url"].ToString() + "\" title=\"" + drSubMenus["mnu_txt"].ToString() + "\">" + drSubMenus["mnu_txt"].ToString() + "<!--[if IE 7]><!--></a><!--<![endif]--><!--[if lte IE 6]><table><tr><td><![endif]-->";
                    obtenSubmenus(drSubMenus["mnu_id"].ToString());
                    elMenu = elMenu + "<!--[if lte IE 6]></td></tr></table></a><![endif]--></li>";
                }
                else
                {
                    elMenu = elMenu + "<li><a href=\"" + drSubMenus["mnu_url"].ToString() + "\" title=\"" + drSubMenus["mnu_txt"].ToString() + "\">" + drSubMenus["mnu_txt"].ToString() + "</a></li>";
                }
            }
            elMenu = elMenu + "</ul>";
            ////cnDatos.Close();
        }
        catch (SqlException ex_TOTSubniv)
        {
            Response.Write("Se ha producido un error: " + ex_TOTSubniv);
        }

        return subMenus;
    }//FIN DE obtenSubmenus(...)
}
[*] el procedimiento almacenado [ObtenerOpciones_Menu]
Código:
CREATE PROCEDURE [ObtenerOpciones_Menu]
AS
	SET NOCOUNT ON
		SELECT *
		FROM MENU
		ORDER BY mnu_posicion, mnu_txt

	SET NOCOUNT OFF
go
y la tabla MENU está creada con estos campos
Código:
 CREATE TABLE MENU (mnu_id INT IDENTITY (1,1) NOT NULL,
 mnu_txt NVARCHAR(50) NOT NULL,
 mnu_title NVARCHAR(50) NULL,
 mnu_padre_id INT NOT NULL CONSTRAINT DF_menu_mnu_padre_id DEFAULT ((0)),
 mnu_posicion TINYINT NOT NULL,
 mnu_url NVARCHAR(50) NOT NULL CONSTRAINT DF_menu_mnu_url DEFAULT (('#')),
 mnu_perfiles NVARCHAR(25) NOT NULL,
 CONSTRAINT clave_menu PRIMARY KEY (mnu_id))
Pues eso, si a alguien le puede hacer falta algo parecido, ya tiene un ejemplo de como hacerlo

No obstante, me interesaría se me aclarara la propuesta de kornissues12, así como lo de cerrar ó no la conexión en ciertas partes dentro de los try ... catch (es mejor cerrarlas ó no importa mucho dejarlas así???).
__________________
Saludos,

zacktagnan.
=================================================
  #7 (permalink)  
Antiguo 24/07/2007, 21:01
Avatar de kornissues12  
Fecha de Ingreso: julio-2007
Mensajes: 4
Antigüedad: 16 años, 9 meses
Puntos: 0
Re: Construir una lista dinámicamente

Bueno creo que te he confundido un poco; ahora bien tienes un error en la apertura de la base por que dentro del "foreach" llamas a la funcion de los menus y dentro de estas abres la base "cnDatos.Open();", por tanto es llamado constantemente una y otra vez, he ahy tu error.

puedes corregirlo, primero conviertes en "static" tus variables:

static SqlConnection cnDatos = new SqlConnection("server=NOMBRE_SERVIDOR;database=NOM BRE_BASEdeDATOS;uid=sa;");

static DataTable dtMenuItems = new DataTable();

de esta forma el valor de las variables permanecera constante entre funciones.
Segundo elimina el "cnDatos.Open();" de tus funciones y colocalo en la siguiente linea:

cnDatos.Open();
try
{
SqlDataAdapter daMenu = new SqlDataAdapter("ObtenerOpciones_Menu", cnDatos);
daMenu.SelectCommand.CommandType = CommandType.StoredProcedure;
daMenu.Fill(dtMenuItems);
foreach (DataRow drMenuItem in dtMenuItems.Rows)
{
...
}
}
catch(...)
{}
finally
{ cnDatos.Close(); }

con esto evitaras el error de apertura.

Con respecto al uso de la instruccion de mi mensaje anterior es con otra vision muy diferente a la tuya para el codigo, ya que yo utilizo para ello el objeto menu de asp y lo contruyo dinamicamente, por ejemplo:

MenuItem mniTemporal = new MenuItem("Inicio", "Inicio", "", "~/inicio.aspx"); //se crea un menuitem para agregarlo
mnuMenu1.Items.Clear(); //solo pa limpiar en caso de tener precargado datos
mnuMenu1.Items.AddAt(0,mniTemporal); //se agrega el item en el index 0
mniTemporal = new MenuItem("Servicio", "Servicio", "", "~/servicio.aspx");
// y si se desea agregar un hijo (childitem)
mnuMenu1.Items[0].ChildItems.Add(mniTemporal);
//en esta intruccion el indice del (Items[X]) debe ser el numero que corresponde al padre
//tomando en cuenta que la indexacion comienza en cero

Espero esto te ayude.
  #8 (permalink)  
Antiguo 25/07/2007, 04:29
Avatar de zacktagnan  
Fecha de Ingreso: abril-2005
Mensajes: 501
Antigüedad: 19 años
Puntos: 3
Re: Construir una lista dinámicamente

Hola de nuevo kornissues12:

He hecho lo que dices respecto a cómo abrir y cerrar adecuadamente la conexión y definir las variables SqlConnection cnDatos y DataTable dtMenuItems a static, quitar lo de abrir y cerrar la conexión dentro de las funciones secundarias llamadas dentro de construirMenu(), quedando así:

Código:
...

static SqlConnection cnDatos = new SqlConnection("server=NOMBRE_SERVIDOR;database=NOM BRE_BASEdeDATOS;uid=sa;");

static DataTable dtMenuItems = new DataTable();

...

protected void Page_Load(object sender, EventArgs e)
{
...
}

protected string construirMenu()
{
...
        //********CONOPEN
        cnDatos.Open();
        try//********TRY
        {
            //RECOGIENDO LOS DATOS DE LA BASE DE DATOS
            //==========================================
            //INVOCANDO AL PROCEDIMIENTO ALMACENADO
            SqlDataAdapter daMenu = new SqlDataAdapter("ObtenerOpciones_Menu", cnDatos);
            daMenu.SelectCommand.CommandType = CommandType.StoredProcedure;
            //LLENANDO EL DataTable
            daMenu.Fill(dtMenuItems);
            //RECORRIENDO EL DataTable PARA AGREGAR LOS ELEMENTOS QUE ESTARÁN EN LA CABECERA DEL MENÚ
            foreach (DataRow drMenuItem in dtMenuItems.Rows)
            {
                //VER SI HAY SUBMENÚS PARA EL NIVEL SUPERIOR RECORRIDO
                haySubmenus(drMenuItem["mnu_id"].ToString());
                if (total_TOTSubniv > 0)
                {
                    //HABIENDO SUBMENÚS
                    //====================================================
                    /*Response.Write("[drMenuItem[\"mnu_perfiles\"].ToString()] = " + drMenuItem["mnu_perfiles"].ToString());*/
                    //>>>> COMPROBANDO PERFILES VÁLIDOS
                    perfiles_ok(drMenuItem["mnu_perfiles"].ToString());
                    //SÓLO SI PERFIL VÁLIDO
                    if (menu_ok > 0)
                    {/**///*****************************************
                        ////Response.Write("<BR />El Menú [" + drMenuItem["mnu_txt"].ToString() + "] tiene " + total_TOTSubniv + " submenú(s)");
                        //ESTA CONDICION INDICA QUE SON ELEMENTOS PADRE
                        if (drMenuItem["mnu_id"].ToString() == drMenuItem["mnu_padre_id"].ToString())
                        {
                            elMenu = elMenu + "<li><a href=\"" + drMenuItem["mnu_url"].ToString() + "\">" + (drMenuItem["mnu_txt"].ToString()).ToUpper() + "<!--[if IE 7]><!--></a><!--<![endif]--><!--[if lte IE 6]><table><tr><td><![endif]-->";
                            obtenSubmenus(drMenuItem["mnu_id"].ToString());
                            elMenu = elMenu + "<!--[if lte IE 6]></td></tr></table></a><![endif]--></li>";
                        }
                    }//FIN DE SÓLO SI PERFIL VÁLIDO/**///*****************************************
                }
                else
                {
                    //NO HABIENDO SUBMENÚS
                    //====================================================
                    //>>>> COMPROBANDO PERFILES VÁLIDOS
                    perfiles_ok(drMenuItem["mnu_perfiles"].ToString());
                    //SÓLO SI PERFIL VÁLIDO
                    //Y SIENDO MENÚS QUE VAN SIN SUBMENÚS POR DEFECTO
                    if (menu_ok > 0 && bool.Parse(drMenuItem["mnu_nosubmnus"].ToString()) == true)
                    {/**///*****************************************
                        //ESTA CONDICION INDICA QUE SON ELEMENTOS PADRE
                        if (drMenuItem["mnu_id"].ToString() == drMenuItem["mnu_padre_id"].ToString())
                        {
                            elMenu = elMenu + "<li><a href=\"" + drMenuItem["mnu_url"].ToString() + "\">" + drMenuItem["mnu_txt"].ToString().ToUpper() + "</a></li>";
                        }
                    }//FIN DE SÓLO SI PERFIL VÁLIDO/**///*****************************************
                }
            }//fin foreach
        }//********FIN TRY
        //********CATCH
        catch (SqlException ex_construirMenu)
        {
            Response.Write("Se ha producido un error: " + ex_construirMenu);
        }//********FIN CATCH
        //********FINALLY//********CONCLOSE
        finally
        {
            cnDatos.Close();
        }
...
}
y en las funciones quitando ó comentando las aperturas y cierres de conexión que había:
Código:
    protected int haySubmenus(string menuId)
    {
        string sql_TOTSubniv = "SELECT COUNT(mnu_id) FROM MENU WHERE mnu_padre_id=" + menuId + " AND mnu_id<>" + menuId + " AND mnu_perfiles LIKE '%" + (Session["perfil_id"]).ToString() + "%'";
        SqlCommand coman_TOTSubniv = new SqlCommand(sql_TOTSubniv, cnDatos);

        try
        {
            ////cnDatos.Open();
            //RECOGIENDO EL RESULTADO DEL COUNT(mnu_id)
            total_TOTSubniv = int.Parse(coman_TOTSubniv.ExecuteScalar().ToString());
            ////cnDatos.Close();
        }
        catch (SqlException ex_TOTSubniv)
        {
            Response.Write("Se ha producido un error: " + ex_TOTSubniv);
        }

        return total_TOTSubniv;
    }//FIN DE haySubmenus(...)

    protected string obtenSubmenus(string menuId)
    {
        DataTable dtSubMenus = new DataTable();
        SqlDataAdapter daSubMenus = new SqlDataAdapter("SELECT * FROM MENU WHERE mnu_padre_id=" + menuId + " AND mnu_id<>" + menuId + " AND mnu_perfiles LIKE '%" + (Session["perfil_id"]).ToString() + "%'" + " ORDER BY mnu_posicion, mnu_txt", cnDatos);
        //daSubMenus.SelectCommand.CommandType = CommandType.StoredProcedure;
        //LLENANDO EL DataTable
        daSubMenus.Fill(dtSubMenus);
        try
        {
            ////cnDatos.Open();
            elMenu = elMenu + "<ul>";
            foreach (DataRow drSubMenus in dtSubMenus.Rows)
            {
                haySubmenus(drSubMenus["mnu_id"].ToString());
                if (total_TOTSubniv > 0)
                {
                    //HABIENDO SUBMENÚS
                    //====================================================
                    //>>>> COMPROBANDO PERFILES VÁLIDOS
                    perfiles_ok(drSubMenus["mnu_perfiles"].ToString());
                    //SÓLO SI PERFIL VÁLIDO
                    if (menu_ok > 0)
                    {/**///*****************************************
                        elMenu = elMenu + "<li><a class=\"drop\" href=\"" + drSubMenus["mnu_url"].ToString() + "\" title=\"" + drSubMenus["mnu_txt"].ToString() + "\">" + drSubMenus["mnu_txt"].ToString() + "<!--[if IE 7]><!--></a><!--<![endif]--><!--[if lte IE 6]><table><tr><td><![endif]-->";
                        obtenSubmenus(drSubMenus["mnu_id"].ToString());
                        elMenu = elMenu + "<!--[if lte IE 6]></td></tr></table></a><![endif]--></li>";
                    }/**///*****************************************
                }
                else
                {
                    //NO HABIENDO SUBMENÚS
                    //====================================================
                    //>>>> COMPROBANDO PERFILES VÁLIDOS
                    perfiles_ok(drSubMenus["mnu_perfiles"].ToString());
                    //SÓLO SI PERFIL VÁLIDO
                    //Y SIENDO MENÚS QUE VAN SIN SUBMENÚS POR DEFECTO
                    if (menu_ok > 0 && bool.Parse(drSubMenus["mnu_nosubmnus"].ToString()) == true)
                    {/**///*****************************************
                        elMenu = elMenu + "<li><a href=\"" + drSubMenus["mnu_url"].ToString() + "\" title=\"" + drSubMenus["mnu_txt"].ToString() + "\">" + drSubMenus["mnu_txt"].ToString() + "</a></li>";
                    }/**///*****************************************
                }
            }
            elMenu = elMenu + "</ul>";
            ////cnDatos.Close();
        }
        catch (SqlException ex_TOTSubniv)
        {
            Response.Write("Se ha producido un error: " + ex_TOTSubniv);
        }

        return subMenus;
    }//FIN DE obtenSubmenus(...)

En principio, parece que no debería dar problema. Y lo he subido a internet y va.

La cosa es que se me ha ocurrido actualizar la página y entonces me duplica el menú. Es decir, por cada actualización de página me construye de nuevo el menú...

No sé por qué será está cosa...

Total que me ha dado por probar a quitar la definición static de las variables mencionadas, y entonces no me produce ningún error.

Código:
SqlConnection cnDatos = new SqlConnection("server=NOMBRE_SERVIDOR;database=NOM BRE_BASEdeDATOS;uid=sa;");

DataTable dtMenuItems = new DataTable();
¿¿¿Sabes la explicación de esto???

Respecto a lo otro que explicas, trataré de mirarlo en cuánto tenga algo de tiempo libre. Gracias.
__________________
Saludos,

zacktagnan.
=================================================
  #9 (permalink)  
Antiguo 25/07/2007, 20:56
Avatar de kornissues12  
Fecha de Ingreso: julio-2007
Mensajes: 4
Antigüedad: 16 años, 9 meses
Puntos: 0
Re: Construir una lista dinámicamente

Hola que bueno que te sirvio, ahora hay un pequeño error bueno no precisamente un erro pero es mucho mejor para el control de errores poner el cnDatos.Open(); dentro del try.

Bien ahora lo que sucede es que tu datetable mantiene la tabla anterior por tanto agrega denuevo la tabla cuando llama a la funcion sin borrar la anterior, esto lo puedes arreglar limpiendo la variable:

dtMenuItems=null;

antes del return, o puedes poner una condicion antes del try por ejemplo:

if(!isPostback)
{
try
{ ... }
}
else
{ return ""; //bueno esto si te genera un error pidiendote un return
o
return elMenu; //el que te sirva mejor, yo prefiero este ya que refresca el menu
}

espero te sirva
  #10 (permalink)  
Antiguo 26/07/2007, 02:15
Avatar de zacktagnan  
Fecha de Ingreso: abril-2005
Mensajes: 501
Antigüedad: 19 años
Puntos: 3
Re: Construir una lista dinámicamente

De antemano, gracias por seguir respondiendo.

Vamos a ver:

De primeras he vuelto a poner las variables a static

- He querido probar a poner lo del null para el DataTable dtMenuItems de esta forma, como decías antes del return:

Código:
        ...
        
        elMenu = elMenu + "</ul>";

        dtMenuItems = null;
        return elMenu;
Y cuando actualizo, me dice que "...el DataTable no puede ser nulo..."

Luego he querido probar lo del try.

Según como tu lo planteabas...:
Cita:
Código:
if(!isPostback)
{
try
{ ... }
}
else
{ return ""; //bueno esto si te genera un error pidiendote un return
o
return elMenu; //el que te sirva mejor, yo prefiero este ya que refresca el menu
}
...solo va a devolver algo todas las veces menos la primera, es decir que la primera vez que se accede a la página no pasará por el return y entonces da error por no llegar a él.

Entonces yo lo he puesto así, sin else:

Código:
if(!isPostback)
{
try
{ ... }
catch() {}
finally {}
        elMenu = elMenu + "</ul>";
}

        ////////dtMenuItems = null;
        return elMenu;
Entonces me vuelve a lo de repetir el menú cada vez que actualizo...

Así, si no hay otra sugerencia, lo dejo como estaba antes de tu último mensaje...

Gracias de nuevo.
__________________
Saludos,

zacktagnan.
=================================================
  #11 (permalink)  
Antiguo 26/07/2007, 21:13
Avatar de kornissues12  
Fecha de Ingreso: julio-2007
Mensajes: 4
Antigüedad: 16 años, 9 meses
Puntos: 0
Re: Construir una lista dinámicamente

Hola y de nada es bueno compartir conocimiento, bueno ya revisando detenidamente puedes colocar un return dentro del primer if, recuerda al final del mismo; asi entre al if o else tendra un return.
acerca del datatable, realmente no puede ser null pero puedes vaciar la variable:

dtMenuItems = new DataTable();

asi se reinicia la variable, espero que esto te sirva y lamento si te confundi mas lo siento.
si deseas puedes contactarme directamente en kornissues12@gmail
  #12 (permalink)  
Antiguo 27/07/2007, 00:43
Avatar de zacktagnan  
Fecha de Ingreso: abril-2005
Mensajes: 501
Antigüedad: 19 años
Puntos: 3
Re: Construir una lista dinámicamente

No había puesto eso pero ya había probado a poner un return para el if y para el else Pero bueno pruebo de nuevo así:

Código:
if(!Page.IsPostBack)
{
    elMenu = "<ul>";

    try {}
    catch {}
    finallally {}

    elMenu = "</ul>";
    return elMenu;
}
else
{
    dtMenuItems = new DataTable();
    return elMenu;
}
Con el dtMenuItems = new DataTable(); no me da error, pero en páginas dónde hay un post, por ser un gridview para actualizar datos ó paginado, entonces el menú no llega a construirse.

Por eso también volví a como estaba antes...
__________________
Saludos,

zacktagnan.
=================================================
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta

SíEste tema le ha gustado a 1 personas




La zona horaria es GMT -6. Ahora son las 23:54.