Posted by: Sr Coelho | 26/01/2012

Menu Dinâmico .Net C#

Menu Tree ViewNesse artigo vamos mostrar como criar um menu dinâmico em .Net C#. A ideia é buscar os dados do menu em um banco dados, previamente cadastrado, e montar o menu, de acordo com essas informações. O menu pode ser do tipo que você quiser, no exemplo utilizamos o System.Web.UI.WebControls.Menu

Segue abaixo uma ideia para tabela que armazenará os dados do menu:

CREATE TABLE [dbo].[Menu]
(
[ID_Menu]    [INT] NOT NULL,-- ID
[Name]       [VARCHAR](50),-- Nome dos itens do menu
[ParentMenu] [INT] NULL,-- ID do item do menu pai
[Link]       [VARCHAR](250) NULL,-- Link acionado ao clicar no menu
[OrderMenu]  [INT] NULL, -- Ordem dos itens do menu
)

Ok, então todos os itens do menu virão dessa tabela, você precisa ter atenção para cadastrar os itens corretamente, caso contrário o menu ficará errado.

Você deve criar uma rotina para ler a tabela acima e armazenar os dados dentro de um DataSet, feito isso, o código abaixo irá percorrer o dataset montando o menu.

public void MontarMenu(Menu myMenu)
{
   ...
   foreach(DataRow drMenuItens in dsMenu.Tables[0].Rows)
   {
      if (ChecarRoot(drMenuItens))
         CriarMenu(myMenu, CriarItem(drMenuItens), null, dsMenu.Tables[0]);
   }
}

Verifique que o método CriarMenu (linha 7) só é chamado quando o método ChecarRoot (linha 6) retorna true. Vamos verificar exatamente o que esse método faz.

private bool ChecarRoot(DataRow rowMenu)
{
   return rowMenu["ParentMenu"].Equals(DBNull.Value);
}

O ChecarRoot simplesmente verifica se o item de menu não tem pai, ou seja, é o primeiro menu. Agora vejamos o método CriarItem.

private MenuItem CriarItem(DataRow rowMenu)
{
   MenuItem item = new MenuItem();

   if (!rowMenu["Name"].Equals(DBNull.Value))
      item.Text = rowMenu["Name"].ToString()

   if (!rowMenu["ID_menu"].Equals(DBNull.Value))
      item.Value = rowMenu["ID_menu"].ToString();

   if (!rowMenu["Link"].Equals(DBNull.Value))
      item.NavigateUrl = rowMenu["Link"].ToString();

   return item;
}

O método CriarItem cria o item de menu propriamente dito, de acordo com os valores armazenados na tabela. Caso queira adicionar algum atributo novo ao menu, como um ícone, por exemplo, esse é o lugar.

Agora vem o X da questão, método CriarMenu.

private void CriarMenu(Menu myMenu, MenuItem itemCorrente, MenuItem itemPai, DataTable dtMenu)
{
   if (itemPai == null)
      myMenu.Items.Add(itemCorrente);
   else
      itemPai.ChildItems.Add(itemCorrente);

   DataRow[] rowsChild = dtMenu.Select("ParentMenu = " + itemCorrente.Value);

   for (int idx = 0; idx < rowsChild.Length; idx++)
   {
      CriarMenu(myMenu, CriarItem(rowsChild[idx]), itemCorrente, dtMenu);
   }
}

Eis o cérebro da coisa… O método CriarMenu… Ele é o método responsável por efetivamente criar o menu. Ele funciona de forma recursiva, pois assim o menu não tem limites de níveis.

Como todo bom programador ou analista, você quer pular o blá blá blá e ir direto ao fonte, certo? Beleza… então baixe o fonte de exemplo e adeque a sua necessidade e lembre-se na natureza nada se cria tudo se transforma.

Update 10/07/2013:  Publicado um novo post sobre esse assunto utilizando técnicas mais modernas de programação. Ver post.

Download do arquivo: menu.cs

Enjoy iT


Sr. Coelho

Gostou? Visite Artigos do Sr. Coelho para mais dicas.


Responses

  1. Como você configurou o Menu, para ficar com esse Layout Bonito? Poderia passar o código, por gentileza?

    • Oi Jaqueline, verifique o método CriarItem(), nele podemos fazer a atribuição de qualquer propriedade do item de menu que estamos montando. Nesse momento vc pode utilizar a propriedade “Icon” e atribuir uma imagem para o seu item de menu.

      Exemplo:
      menutItem.Icon = new System.Windows.Controls.Image { Source = new BitmapImage(new Uri(“images/sample.png”, UriKind.Relative)) };

  2. Qual versão do VS você usou? De onde vem a classe SecureIT.Security ?

    • Olá Fernando. Usei o VS 2010, mas deve funcionar em versões anteriores tb.

      Quanto a classe SecureIT.Security, ela faz parte de um outro projeto que montei. Na montagem do menu, o sistema chama o método GetMenuTable() dessa classe, que no caso, consulta a tabela no banco de dados, onde está a estrutura do menu (ver exemplo de criação da tabela que eu citei) , ela devolve um dataset de acordo com os dados encontrados no banco, e baseado nesse dataset, o menu será montado.

      Espero ter ajudado.

      Abraço.

  3. tentei criar um quarto nível de menu, algo como “forum > Abertura > Atração > quarto nivel do menu”, mas ele só foi até o terceiro nível ( “atração”), existe alguma limitação ? você já testou com mais de 3 níveis ?

    • Oi Maurício, da maneira como foi criado o menu de exemplo do post, não há limite de níveis, pois a rotina é recursiva, ou seja, ela vai chamando ela mesma e montando quantos níveis houverem cadastrados no banco de dados.

  4. Obrigado Sr Coelho,
    realmente a recursividade com que foi desenvolvida sua programação é ilimitada, no meu caso ( talvez interesse para outros que poderão cair na mesma “armadilha”) a limitação estava na propriedade “MaximumDynamicDisplayLevels” do controle Menu do .net., que estava limitada a 3 níveis.

    • Boa Maurício, obrigado pela dica. No meu caso eu usei o “System.Windows.Forms.MenuStrip” e ele não tem essa propriedade.

  5. Ótimo guia!!

    Sr. Coelho, estou com um probleminha poderia me ajudar ?

    Eu utilizei o exemplo que você criou, porém quando eu clico em algum “pai”, ele duplica todos os pais.

    O click nos filhos funciona direitinho, mas nos pais não:/

    Poderia me ajudar ?

    Obrigado!

    • Bom dia Rafael.

      Primeiramente, obrigado pela visita e pelo comentário.

      Bem, não entendi exatamente o seu problema. O menu é montado corretamente e depois quando vc clica em algum item (que é pai) ele da esse problema de duplicar? É isso?
      No caso do exemplo, a única coisa que deveria ocorrer quando alguém clica em algum item do menu, é ele acionar a url configurada na tem.NavigateUrl.

      • Isso, por exemplo, os meus “Pais” são Home, About, Cadastro.

        Quando eu clico em algum deles, ele duplica, então fica Home, About, Cadastro. Home, About, Cadastro.

      • Entendi, mas é como expliquei no outro comentário, a única ação que o menu deveria tomar é a descrita no item.NavigateUrl, será que quando clica no menu vc não está chamando a rotina de criar menu novamente?

        Lembre-se de que, se estiver usando páginas aspx, a rotina que aciona a criação do menu deve estar dentro de um if (!Page.IsPostBack), por exemplo:

        private void Page_Load()
        {
            if (!Page.IsPostBack)
            {
                // Chama a rotina para criação do menu
                CriarMeuMenu();
            }
        }
        

        Espero ter ajudado.

        Abraço.

  6. Obrigado. Muito bom teu tutorial!!!

  7. Sr Coelho, Parabéns pelo site! o conteúdo é de primeira”

    Poderia me ajudar com uma questão?, estou montando um menu dinamicamente de acordo com o fonte exibido por você acima, o meu problema está na lentidão. Meu menu esta dividido em 5 tabelas, cada tabela representa um nível, logo são 5 níveis. Teria uma dica de como popular o DataSet a ser percorrido? Estou realizando muitos selects pois a cada estrutura, eu realizo um select e populo o dataSet, mas esta operação é lenta.

    Grato desde já!
    Atenciosamente Rafael T.

  8. Tks! me ajudou bastante, troquei o componente utilizando treeview, então nos lugares de item utilizei nodes. Muito obrigado.

  9. Obrigada me ajudou bastante tbm, muito simples, agora meu menu pode ter N niveis rsrs, sempre peno um pouco pra fazer recursividade , agora foi fácil com tudo mastigado, fiz adaptações, usei treeview e ficou jóia.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: