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?