Recorrer la estructura de un menú por código

A partir de Visual Studio 2005, el diseño de menús para Windows Forms experimentó una mejora considerable gracias a la incorporación de la clase MenuStrip a la plataforma .NET, a la que acompañaban también todo el conjunto de clases relacionadas con ella: ToolStripMenuItem, ToolStripSeparator, ToolStripTextBox, etc., y que incrementaban notablemente las funcionalidades aportadas por la clase dedicada hasta ese momento a tales menesteres: MainMenu.

La creación de un menú utilizando la clase MenuStrip, nos permite definir sus opciones con características que están más allá del mero literal que muestra el título de la opción, siendo posible que su comportamiento sea el de una caja de texto o una lista desplegable.

No obstante, la finalidad del presente artículo no es mostrar las características particulares de tales tipos de opción de menú, sino exponer un ejemplo que nos permita recorrer su estructura de opciones, realizando cambios en las mismas, en función de si pertenecen a un tipo determinado o poseen ciertas características.

Para ello partiremos de un formulario al que añadiremos un menú con el conjunto de opciones que vemos en la siguiente imagen.

Entre las opciones de este menú podemos observar (indicadas con flechas en la imagen) que se encuentran dos de tipo caja de texto -objetos ToolStripTextBox-, mientras que en el resto existen algunas cuyo literal comienza por minúscula. El objetivo del proceso a desarrollar será cambiar a negrita y cursiva el tipo de letra de las opciones situadas en la barra de menú, convertir a mayúscula el contenido de las opciones de tipo ToolStripTextBox, y situar una marca de verificación junto a las opciones que empiezan por minúscula.

Dado que un menú puede organizarse -tal y como vemos en este ejemplo- en opciones que a su vez despliegan nuevos conjuntos de opciones dependientes, se hace necesario implementar un algoritmo recursivo que permita llegar a todos los niveles de submenús existentes en su estructura.

Sin embargo, antes que entrar en la creación de dicho algoritmo, nos ocuparemos de las dos opciones que se encuentran en la barra de menú, cuyo tipo de letra vamos a convertir a negrita y cursiva recorriendo la colección MenuStrip.Items como vemos a continuación. Todas las operaciones de transformación del menú las realizaremos desde el evento Click de un control Button situado en el formulario.

private void btnModificar_Click(object sender, EventArgs e)
{
    // crear un nuevo tipo de letra para las opciones de la barra de menú
    Font fntTipoLetra = new Font(menuStrip1.Items[0].Font.FontFamily,
        menuStrip1.Items[0].Font.Size,
        FontStyle.Bold | FontStyle.Italic);

    // recorrer las opciones del menú
    foreach (ToolStripMenuItem mnuitOpcion in this.menuStrip1.Items)
    {
        // cambiar el tipo de letra
        mnuitOpcion.Font = fntTipoLetra;
    }
}

Después de ejecutar el anterior código habremos realizado la transformación de las opciones de menú de la barra... ¡¡¡y también del resto de opciones!!! =8-O, ya que un cambio de estas características, realizado en la opción principal de la barra, se propaga al resto de opciones del mismo tipo que dicha opción despliega, por lo que las opciones de tipo ToolStripTextBox no se verán afectadas.

Puesto que solamente deseamos modificar el tipo de letra en la barra de menú, guardaremos el objeto Font original en una variable, restaurándolo al recorrer las opciones de los menús desplegables.

En lo que respecta al proceso encargado de recorrer estos menús desplegables, el modo de detectar si una opción de menú tiene un submenú asociado, pasa por comprobar su propiedad DropDownItems, la cual es una colección de objetos ToolStripItem.

private void btnModificar_Click(object sender, EventArgs e)
{
    // obtener el tipo de letra original de las opciones de menú
    // para restaurarlo en las opciones desplegables
    Font fntOriginal = this.menuStrip1.Items[0].Font;
    //....
    // recorrer las opciones del menú
    foreach (ToolStripMenuItem mnuitOpcion in this.menuStrip1.Items)
    {
        //....
        // si esta opción despliega un submenú
        // llamar a un método para hacer cambios
        // en las opciones del submenú
        if (mnuitOpcion.DropDownItems.Count > 0)
        {                    
            this.CambiarOpcionesMenu(mnuitOpcion.DropDownItems, fntOriginal);
        }
    }
}

Para cada opción de menú situada en la barra comprobaremos si despliega un submenú, y en caso afirmativo, llamaremos a un método con el nombre CambiarOpcionesMenu, que será ejecutado recursivamente cada vez que volvamos a encontrarnos con una opción que despliegue nuevos elementos. Este método recibirá como parámetros la colección de opciones a recorrer, y el objeto Font original a restaurar sobre las opciones.

private void CambiarOpcionesMenu(ToolStripItemCollection colOpcionesMenu, Font fntTipoOriginal)
{
    // recorrer el submenú
    foreach (ToolStripItem itmOpcion in colOpcionesMenu)
    {
        //....
        // si esta opción a su vez despliega un nuevo submenú
        // llamar recursivamente a este método para cambiar sus opciones
        if (((ToolStripMenuItem)itmOpcion).DropDownItems.Count > 0)
        {
             this.CambiarOpcionesMenu(((ToolStripMenuItem)itmOpcion).DropDownItems,
                 fntTipoOriginal);
         }
    }
}

Al recorrer la colección ToolStripItemCollection, cada uno de sus elementos es un tipo de la clase base ToolStripItem. Es por ello que deberemos realizar una operación de conversión de tipos, para obtener el tipo de opción adecuado, y aplicarle los cambios pertinentes cuando sea necesario. Seguidamente podemos ver el código fuente del ejemplo al completo.

private void btnModificar_Click(object sender, EventArgs e)
{
    // obtener el tipo de letra original de las opciones de menú
    // para restaurarlo en las opciones desplegables
    Font fntOriginal = this.menuStrip1.Items[0].Font;

    // crear un nuevo tipo de letra para las opciones de la barra de menú
    Font fntTipoLetra = new Font(menuStrip1.Items[0].Font.FontFamily,
        menuStrip1.Items[0].Font.Size,
        FontStyle.Bold | FontStyle.Italic);

    // recorrer las opciones del menú
    foreach (ToolStripMenuItem mnuitOpcion in this.menuStrip1.Items)
    {
        // cambiar el tipo de letra
        mnuitOpcion.Font = fntTipoLetra;

        // si esta opción despliega un submenú
        // llamar a un método para hacer cambios
        // en las opciones del submenú
        if (mnuitOpcion.DropDownItems.Count > 0)
        {
            this.CambiarOpcionesMenu(mnuitOpcion.DropDownItems, fntOriginal);
        }
    }
}

private void CambiarOpcionesMenu(ToolStripItemCollection colOpcionesMenu, Font fntTipoOriginal)
{
    // recorrer el submenú
    foreach (ToolStripItem itmOpcion in colOpcionesMenu)
    {
        // restaurar el tipo de letra original
        itmOpcion.Font = fntTipoOriginal;

        // si la opción de menú es de tipo caja de texto
        // pasar su contenido a mayúsculas
        if (itmOpcion.GetType() == typeof(ToolStripTextBox))
        {
            itmOpcion.Text = itmOpcion.Text.ToUpper();
        }

        // si es una opción de menú normal...
        if (itmOpcion.GetType() == typeof(ToolStripMenuItem))
        {
            // ... y el primer caracter está en minúscula
            // poner en la opción una marca de verificación
            if (char.IsLower(itmOpcion.Text.ToCharArray(0, 1)[0]))
            {
                ((ToolStripMenuItem)itmOpcion).Checked = true;
            }

            // si esta opción a su vez despliega un nuevo submenú
            // llamar recursivamente a este método para cambiar sus opciones
            if (((ToolStripMenuItem)itmOpcion).DropDownItems.Count > 0)
            {
                this.CambiarOpcionesMenu(((ToolStripMenuItem)itmOpcion).DropDownItems,
                    fntTipoOriginal);
            }
        }
    }
}

En la siguiente imagen podemos ver el resultado de ejecutar el anterior código sobre nuestro menú, con el que hemos logrado modificar dinámicamente las propiedades de sus elementos.

Los proyectos de Visual Studio con los fuentes correspondientes a este ejemplo, pueden descargarse en los siguientes enlaces para C# y VB.

Espero que os resulte de utilidad.

Un saludo.

Published 2/2/2008 13:43 por Luis Miguel Blanco
Archivado en:
Comparte este post:

Comentarios

Tuesday, February 19, 2008 5:42 PM por Alvaro Guzman

# re: Recorrer la estructura de un menú por código

Excelente.  Como se traduce a VB net

Tuesday, February 19, 2008 5:54 PM por Luis Miguel Blanco

# re: Recorrer la estructura de un menú por código

Hola Álvaro

Gracias por tu opinión 8-).Al final del post tienes un par de enlaces desde los que puedes descargar el código fuente, uno de ellos corresponde a VB.

Un saludo,

Luismi

Sunday, May 18, 2008 2:44 PM por Jurahack

# re: Recorrer la estructura de un menú por código

Exelente, gracias por compartir tus conocmientos, me sirvio de mucho,

Monday, May 19, 2008 10:36 AM por Luis Miguel Blanco

# re: Recorrer la estructura de un menú por código

Hola Jurahack

Muchas gracias por tu interés en el artículo, y me alegra que te haya sido de utilidad.

Un saludo.

Luismi

Tuesday, June 3, 2008 2:58 AM por karl

# re: Recorrer la estructura de un menú por código

temas interesantes

Tuesday, June 3, 2008 8:46 AM por Luis Miguel Blanco

# re: Recorrer la estructura de un menú por código

Hola karl

Gracias por leer el post y por tu opinión, espero que te resulte de ayuda.

Un saludo.

Luismi

Wednesday, June 18, 2008 6:18 PM por Pavel

# re: Recorrer la estructura de un menú por código

Excelente el articulo lo necesitaba, me ayudo muchisimo... Gracias =)

Wednesday, June 18, 2008 7:26 PM por Luis Miguel Blanco

# re: Recorrer la estructura de un menú por código

Hola Pavel

Muchas gracias a tí por leer el artículo y me alegra que te resultara útil 8-)

Un saludo,

Luismi

Sunday, July 13, 2008 8:59 PM por CORINA

# re: Recorrer la estructura de un menú por código

QUIERO SABER MAS QUE OTRO

Wednesday, October 29, 2008 1:40 PM por mariano

# re: Recorrer la estructura de un menú por código

y en visual basic 6??

Saturday, January 24, 2009 1:39 PM por Albert

# re: Recorrer la estructura de un menú por código

Interesante post, me ha servidor para tomar un par de ideas para traducir tanto un MenuStrip como un TreeView (funcionan parecido). Gracias por el trabajo.

Friday, January 30, 2009 8:49 PM por Luis Felipe

# re: Recorrer la estructura de un menú por código

Excelente ejemplo, pero tengo una consulta.

Necesito hacer que el menu no se oculte al hacer clic en el ultimo hijo del menu.

Lo necesito porque en mi aplicación tengo que dejar varias opciones del menu en checkeadas a la vez, pero al esconderse el menu cuando hago clic tengo que volver a recorrer el menu completo por cada vez que checkeo el ultimo hijo del arbol del menu... no se si me entiendes.

Ejemplo:

Menu

..opcion1

....sub opcion 1

....sub opcion 2

....sub opcion 3

....sub opcion 4

....sub opcion 5

la idea es poder dejar checkeadas algunas de las sub opciones sin tener que recorrer todo el menu por cada opcion que quiero chekear.

Eso, ojala sepas como podría hacerlo.

Gracias.

Thursday, February 12, 2009 1:18 PM por Luis Miguel Blanco

# re: Recorrer la estructura de un menú por código

Hola Albert

Gracias por tu interés en el post y me alegra que te haya sido de utilidad.

Un saludo.

Luismi

Saturday, February 14, 2009 7:48 AM por Luis Miguel Blanco

# re: Recorrer la estructura de un menú por código

Hola Luis Felipe

Gracias por tu opinión sobre el post, y respecto al problema que mencionas, creo que lo podrías resolver de la siguiente manera:

Supongamos que tienes un menú con esta estructura:

-Archivo

----Abrir

----Guardar

----Guardar como

----Salir

En la opción Archivo, asignas a su propiedad Text el valor &Archivo, lo que nos permite acceder a esta opción a través de la combinación de teclas ALT+a para desplegarlo.

Para el resto de opciones, en la propiedad CheckOnClick asignas el valor True.

A continuación pasamos al código del formulario y asociamos varias  opciones desplegadas al mismo manipulador de evento Click. En este manipulador, a través de la clase SendKeys, obligamos a que cuando se pulse sobre una de las opciones, se envíe la combinación de teclado ALT+a, lo que vuelve a desplegar el menú.

//-----------------------------

public partial class Form1 : Form

{

   public Form1()

   {

       InitializeComponent();

       this.abrirToolStripMenuItem.Click += DesplegarMenu;

       this.guardarToolStripMenuItem.Click += DesplegarMenu;

       this.guardarComoToolStripMenuItem.Click += DesplegarMenu;

   }

   private void DesplegarMenu(object sender, EventArgs e)

   {

       SendKeys.Send("%a");

   }

}

//-----------------------------

Espero que te sirva para solucionar tu caso.

Un saludo.

Luismi

Wednesday, June 17, 2009 3:37 PM por live82

# hola: neceito ayuda-......

necesito enlazar varios formularioa en VB y no se me a dado....espero me ayuden...

archivo

   clientes

   empresa

algo asi...pero en visual 6.. es facil...pero ahora con el visual 2008..estoy algo perdida...espero me puedan ayudar....gracias

Sunday, July 12, 2009 2:46 PM por Sergio

# re: Recorrer la estructura de un menú por código en VB 6

Barbaro Luis. Lo que necesito es visualizar o no una opecion del menu dependiendo del perfil de usario que se le elija.

Ejemplo: si el usuario es operativo solo dejar que acceda a la opcion de "venta". Por supuesto que las otras opciones de menu estaran en otro estado.

Gracias

Sunday, July 26, 2009 9:53 PM por Luis Miguel Blanco

# re: Recorrer la estructura de un menú por código

Hola Sergio

Antes de ejecutar el proceso que recorre la estructura de opciones del menú, puedes obtener el perfil del usuario y comprobar sus características, de modo que en el proceso que recorre el menú, si el usuario que ha accedido a la aplicación no tiene permisos para ver unas determinadas opciones, a la propiedad Visible de dichas opciones le asignas el valor False.

Para almacenar el perfil del usuario supongo que puedes utilizar una base de datos en la que tengas una tabla con los usuarios y otra con las opciones a las que los diferentes usuarios tienen acceso.

Un saludo.

Luismi

Monday, September 14, 2009 12:22 PM por Diego

# re: Recorrer la estructura de un menú por código

Muy bueno el artículo, pero cómo puedo saber si al recorrer el MenuStrip, el elemento en el que estoy es de nivel superior, o es dependiente de otro. Ejemplo: Archivo --> Abrir

Gracias.

Sunday, September 20, 2009 10:57 PM por Luis Miguel Blanco

# re: Recorrer la estructura de un menú por código

Hola Diego

Gracias por tu opinión, y respecto a tu pregunta, una posible solución sería utilizar una variable numérica, en la que asignaremos el número de nivel, cada vez que vayamos a entrar en un grupo de opciones de menú, algo similar a lo siguiente:

//---------------------------------

public partial class Form1 : Form

{

   private int nNivel = 0;

   //....

   private void btnModificar_Click(object sender, EventArgs e)

   {

     //....

     if (mnuitOpcion.DropDownItems.Count > 0)

     {

         nNivel++;

         this.CambiarOpcionesMenu(mnuitOpcion.DropDownItems, fntOriginal);

     }

     //....

     private void CambiarOpcionesMenu(ToolStripItemCollection colOpcionesMenu, Font fntTipoOriginal)

     {

       //....

         if (((ToolStripMenuItem)itmOpcion).DropDownItems.Count > 0)

         {                    

             nNivel++;

             this.CambiarOpcionesMenu(((ToolStripMenuItem)itmOpcion).DropDownItems,

                 fntTipoOriginal);

         }

//....

//---------------------------------

Otra forma de resolverlo sería utilizar la propiedad Tag de los objetos ToolStripMenuItem. A esta propiedad le asignaríamos el número de nivel en tiempo de diseño, y en tiempo de ejecución recuperaríamos ese valor para saber en qué nivel del menú nos encontramos.

Un saludo.

Luismi

Friday, December 11, 2009 11:08 PM por blanca

# en viar a un form

es entendible con el ejemplo la forma de funcionamiento de este componente, pero como seria el código para que al hacer click sobre una de las opciones te envie a un form

Friday, December 18, 2009 6:18 PM por Luis Miguel Blanco

# re: Recorrer la estructura de un menú por código

Hola Blanca

Para abrir un nuevo formulario que tengas en tu proyecto al hacer clic en una de las opciones del menú, lo que debes hacer es escribir el manipulador del evento Click de la opción de menú que necesites, y allí realizar la instanciación del nuevo formulario.

Por ejemplo, supongamos que en el proyecto tenemos un formulario llamado frmDatos, y queremos que al hacer clic en la opción Abrir del menú se instancie un nuevo objeto de dicho formulario. El código a utilizar sería el siguiente:

//---------------------------------

private void abrirToolStripMenuItem_Click(object sender, EventArgs e)

{

   frmDatos ofrmDatos = new frmDatos();

   ofrmDatos.Show();

}

//---------------------------------

Un saludo,

Luismi

Wednesday, March 24, 2010 7:32 PM por Tavito

# re: Recorrer la estructura de un menú por código

podrias facilitar el recorrido el del menu para codigo visual basic forms 2005

Thursday, March 25, 2010 8:54 AM por Luis Miguel Blanco

# re: Recorrer la estructura de un menú por código

Hola Tavito

Al final del texto de este post tienes dos enlaces con el código fuente para cada lenguaje: C# y VB.

Un saludo.

Luismi

Friday, March 26, 2010 12:10 AM por vanesa

# re: Recorrer la estructura de un menú por código

mil gracias ya tenia mas de dos dias con esto y no lograba leer todos los subsubsubsubmenus.

La opcion descargable super util

Saturday, March 27, 2010 12:41 PM por Luis Miguel Blanco

# re: Recorrer la estructura de un menú por código

Hola Vanesa

Gracias por el interés en el post y me alegro que te haya servido de ayuda.

Un saludo.

Luismi

Monday, May 3, 2010 11:41 PM por Joehit

# re: Recorrer la estructura de un menú por código

Compadre eres el mejor un verdadero crack saludos desde Panama

Wednesday, May 19, 2010 7:21 PM por Luis Miguel Blanco

# re: Recorrer la estructura de un menú por código

Hola Joehit

Gracias por tu interés en el artículo.

Un saludo

Luismi

Thursday, February 3, 2011 6:36 PM por Marcos

# re: Recorrer la estructura de un menú por código

Haber me parece muy interesante tu nota sobre MenuStrip, haber; si yo quisiera tenes bd con una tabla que me guardara los name de todo el menu excepto los separadores ¿Como lo haria?.

y segundo ,si quisiera Habilitar o Hinabilitar uno o varios menus dependiendo de un rol de usuarios que se guarde en otra table ¿Como lo Haria?

Te recuerdo que trabajo con c# vs2010

Te agradezco mi correo es marcos301 arroba yahoo punto com

Wednesday, February 9, 2011 8:54 PM por Luis Miguel Blanco

# re: Recorrer la estructura de un menú por código

Hola Marcos

Gracias por tu opinión. Respecto al planteamiento que comentas, puedes crear una tabla en tu bbdd con una estructura en la que haya un campo por cada propiedad que necesites controlar para tus opciones de menú: Nombre, Checked, Enabled, etc.

En esta tabla añadirías un registro por cada opción de tu menú. También podrías incluir un campo que serviría como indicador o flag, que según su valor, informara de si la opción tiene a su vez opciones dependientes.

De esta forma, al iniciar tu aplicación, un proceso recursivo, similar al que se expone en este artículo, recorrería tu tabla e iría leyendo los registros y creando los diferentes objetos ToolStripMenuItem, construyendo así el menú del formulario.

Un saludo,

Luismi