Jump to content
Fórum Script Brasil
  • 0

DESAFiO: Criar menus dinamicos em tempo de execucao


Terra Jr

Question

Amigos, tenho um desafio de nível quase intermediário para todos!

Construir uma solução de menus com diversos níveis de forma dinâmica com usando ASP .NET,

buscando informações disponibilizadas de fontes externas (banco de dados, cloud computing, etc).

Calma que é simples. vou explicar...

Imaginem a situação:

Você tem uma tabela chamada MENU com a seguinte estrutura:

NOME        TIPO      TAM   DESCRICAO
 idmenu      NUMERO     11   ID DO MENU
 url         TEXTO     255   URL DA PAGINA QUE SERÁ ABERTA
 idusuario   NUMERO     11   ID DO USUARIO AO QUAL O MENU PERTENCE
 menu        TEXTO      40   NOME EXIBIDO NO MENU
 tooltip     TEXTO     255   LEGENDA EXIBIDA quando O MOUSE FICAR SOBRE
 icone       TEXTO     255   URL ONDE ESTA O ICONE Q SERA EXIBIDO
 idpai       NUMERO     11   ID DO MENU QUE ESTÉ SERÁ FILHO
Ok, até aqui temos a tabela MENUS que contém os menus. Então uma classe fará acesso ao banco de dados para obter os dados dos menus cadastrados para aquele usuário. Após isso a classe irá criar um Objeto System.Web.UI.WebControls.Menu e preencher sua colecao Menu.Items com os menus lidos na tabela menus. Veja que o campo IDPAI guardará o ID do menu que é o Pai. OS que tiverem o IdPai como 0, serão os que será exibidos no primeiro nível. Os que ficariam no ROOT / Por exemplo, imagine a tabela preenchida desta forma:
ID  MENU       IDPAI
1 - Cadastros  0
2 - Consultas  0
4 - Pecas      1
5 - Produtos   1
6 - Vendas     2
Assim teriamos dentro do menu: 1-cadastro os submenus 4-pecas e 5-produtos, e no menu 2-consultas teriamos o submenu 6-vendas Visualmente ficaria assim: 1 - Cadastro 1.1 - Pecas 1.2 - Produtos 2-Consultas 2.1 - Vendas Entendido? Agora ai que está o problema. Veja que tenho como requisito (questões técnicas) que pegar a lista de MENUS em uma única pesquisa SQL. Não posso pesquisar os registros que tem IDPAI = 0, depois percorrer os ID pais e pesquisar os filhos! Assim eu faria diversos SQL numa única exibição do menu! Então montei um cenário bem SIMPLES mas com um lógica incompleta! Gostaria de saber quais as ideias para melhorar o método que alimentará o menu em tempo de execução? Temos então o seguinte, o metodo 'dados.getDataTable(sql)' retorna um DataTable preenchido com o SQL passado como parametro. Assim temos o seguinte código C#:
// SELECT que pega os dados dos menus em ordem de IDPAI, assim temos os PAIS primeiros, depois os filhos...
string sql = "SELECT * FROM menus WHERE idusuario=1 ORDER BY idpai ASC";

// Preenche datatable com os menus
        DataTable dt = dados.getDataTable(sql);

// Pega quantidade de menus cadastrados
        int registros = dt.Rows.Count;

// Cria menu para obter os dados
Menu menu = new Menu();

// Faremos a leitura de todos os registros do DataTable
for (int i = 0; i < registros; i++) {
// Atribui os dados de cada menu
string idpai = dt.Rows[i]["idpai"].ToString();
                string idmenu = dt.Rows[i]["idmenu"].ToString();
                string url = dt.Rows[i]["url"].ToString();
                string menu = dt.Rows[i]["menu"].ToString();
                string tooltip = dt.Rows[i]["tooltip"].ToString();
                string ativo = dt.Rows[i]["ativo"].ToString();
                string icone = dt.Rows[i]["icone"].ToString();

// AQUI ESTA O PROBLEMA, SABEMOS QUE PRIMEIRAMENTE SERAO INSERIDOS
// OS QUE TEM IDPAI=0, QUE são OS MENUS QUE FICARAO NA RAIZ (PRIMEIRO NIVEL)
// MAS COMO COLOCAR OS MENUS FILHOS QUE POSSUIM IDPAI>0 NOS MENUS PAIS CORRESPONDENTES?


// Cria novo item para ser inserido no menu.
MenuItem item = new MenuItem(menu, idmenu, icone, url);
                item.ToolTip = tooltip; // aparece quando o mouse fica sobre o menu!

                int paiSel = int.Parse(idpai);
// SE IDPAI for maior que 0 quer dizer que é um submenu.
if (paiSel > 0) {
               // AQUI ESTA A ZICA!!!
// eu sei qual é o IDPAI e tambem ate o nome do menu pai, mas não dá pra captura-lo!!!
// Pra inserir um submenu nele, pois ele foi criado agora!
} else {
menu.Items.Add(item);
}

Dessa forma, eu poderia criar diversos níveis de submenus apenas inserindo os dados na tabela!!! Sem ter que se preocupar com mudanças no site, pois a manutenção do menu como diversos itens do site seriam dinâmicas, assim fica mais flexível a utilidade do software.

Espero que tenham entendido.! Se alguém saber como fazer isso! Ou se tem outra forma!!

Mas sem utilizar ferramentas de terceiros, o tema do desafio é usar o 'System.Web.UI.WebControls.Menu'.

Obrigado pelo tempo dado a leitura deste desafio! Até mais.

Link to comment
Share on other sites

4 answers to this question

Recommended Posts

  • 0

Cara, bem explicado seu post. Isso (e sem os erros de português) facilita o suporte. Vamos lá...

Você fez o SELECT que trouxe todos os dados referentes a menu. Até ai tudo bem. Você precisa agora montar um loop pra percorrer todos os registros e ir controlando quem é pai e quem é filho. Não sei se há diferença entre o Menu Desktop e o Menu Web, mas segue uma lógica que dá pra você adaptar ai caso seja diferente.

// SELECT que pega os dados dos menus em ordem de IDPAI, assim temos os PAIS primeiros, depois os filhos...
        string sql = "SELECT * FROM menus WHERE idusuario=1 ORDER BY idpai ASC";

        // Preenche datatable com os menus
        DataTable dt = dados.getDataTable(sql);

        // Pega quantidade de menus cadastrados
        int registros = dt.Rows.Count;

        // Cria menu para obter os dados
        Menu menu = new Menu();

        // Faremos a leitura de todos os registros do DataTable
        for (int i = 0; i < registros; i++) {

                // Insere somente os pais
                if dt.Rows[i]["idpai"].ToString() == 0 
                {
                     MenuItem item = new MenuItem(menu, dtRows[i]["idmenu"].ToString(), dt.Rows[i]["icone"].ToString(), dt.Rows[i]["url"].ToString());

             menu.Items.Add(item);                     

             // Pesquisa os próximos registros
                     for (int x = i + 1, x < registros; x++)
                     {
                         if dt.Rows[x]["idpai"].ToString() == dt.Rows[i]["idmenu"].ToString()
                         {
                             menu.Items[menu.Items.Count].ChildItems.Add(new MenuItem(dtRows[x]["idmenu"].ToString(), dt.Rows[x]["icone"].ToString(), dt.Rows[x]["url"].ToString()));
                         }
                     }
                     
                }
        }

Não testei o código, mas isso deve funcionar. Foi uma maneira bem simples de montar, por isso funciona apenas para dois níveis (pai e filho) se um filho tiver um novo filho - Arquivo (pai) -> Novo (filho) -> Projeto (neto) / Pasta (neto) / Mimimi (neto) - ai você teria que montar outra lógica.

Link to comment
Share on other sites

  • 0
// Faremos a leitura de todos os registros do DataTable

for (int i = 0; i < registros; i++) {

// Insere somente os pais

if dt.Rows["idpai"].ToString() == 0

{

MenuItem item = new MenuItem(menu, dtRows["idmenu"].ToString(), dt.Rows["icone"].ToString(), dt.Rows["url"].ToString());

menu.Items.Add(item);

// Pesquisa os próximos registros

for (int x = i + 1, x < registros; x++)

{

if dt.Rows[x]["idpai"].ToString() == dt.Rows["idmenu"].ToString()

{

menu.Items[menu.Items.Count].ChildItems.Add(new MenuItem(dtRows[x]["idmenu"].ToString(), dt.Rows[x]["icone"].ToString(), dt.Rows[x]["url"].ToString()));

}

}

}

}

Não testei o código, mas isso deve funcionar. Foi uma maneira bem simples de montar, por isso funciona apenas para dois níveis (pai e filho) se um filho tiver um novo filho - Arquivo (pai) -> Novo (filho) -> Projeto (neto) / Pasta (neto) / Mimimi (neto) - ai você teria que montar outra lógica.

Obrigado pela resposta amigo.!

Mas infelizmente cai no mesmo problema!

No seu exemplo, voce adiciona o que tem o IDPAI=0 primeiro até ai tudo bem, e faz um outro laço pra inserir os filhos.

Mas o problema é que por exemplo, poderá ter mais que um filho pra cada pai (no caso um menu com vários submenus).

Seguindo seu raciocínio, como você saberia em que posição (MENU) deverá ser inserido o submenu?

Porque você tem um item com um IDPAI=3 por exemplo, isso indica que é um SUBMENU do MENU de código 3.

Mas como você localiza e insere o SUBMENU no System.Web.UI.WebControls.Menu que contém o IDMENU=3 ????? <<- Aqui que tá a jogada!

Eu fiz um que ficou um pouco escroto, mas veja:

string sql = "SELECT * FROM usuariosmenus WHERE idusuario='" + idusuario + "' AND ativo='1' ORDER BY idpai;";
                DataTable dt = dados.getDataTable(sql); // DataTable com os dados do menu desse usuário
                int registros = dt.Rows.Count;

                // Se tiver algum registro (algum menu)
                if (registros > 0) {
                    m.Items.Clear(); // remove registro de erro e alerta...

                    // O SELECT tras os registros com idpai=0 primeiro, assim serão incluídos os pais!
                    // 
                    for (int i = 0; i < registros; i++) {
                        string idpai = dt.Rows[i]["idpai"].ToString();
                        string idmenu = dt.Rows[i]["idmenu"].ToString();
                        string url = dt.Rows[i]["url"].ToString();
                        string menu = dt.Rows[i]["menu"].ToString();
                        string tooltip = dt.Rows[i]["tooltip"].ToString();
                        string ativo = dt.Rows[i]["ativo"].ToString();
                        string icone = dt.Rows[i]["icone"].ToString();

                        MenuItem item = new MenuItem(menu, idmenu, icone, url);
                        item.ToolTip = tooltip;
                
                        int idPaiSelecionado = 0; // usado temporariamente para validar e atribuir o idPai do item selecionado!
                        if (int.TryParse(idpai, out idPaiSelecionado)) {
                            if (idPaiSelecionado.Equals(0)) {
                                m.Items.Add(item);
                            } else {
                                foreach (MenuItem x in m.Items) {
                                    if (x.Value.Equals(idPaiSelecionado)) {
                                        m.Items[m.Items.IndexOf(x)].ChildItems.Add(item);
                                        break; // sai do FOR
                                    }
                                }
                            }
                        }

Mas mesmo assim, tenho que fazer toda configuração visual via código, fica pesado. Pois ele não aproveita a que está já no MasterPage com CSS, entende?!

Mas... se alguém conseguir de um jeito diferente! Posta aqui! Valeu!

Obrigado amigo pela resposta

Link to comment
Share on other sites

  • 0

Veja que no meu exemplo eu insiro no menu sempre um MenuItem. Esse MenuItem sempre será o pai. Nenhum outro item filho será inserido. Quando percorro os demais itens no segundo laço sempre o último item adicionado no menu vai ser o pai que eu vou verificar se tem filhos.

Ou seja, tomando como exemplo essa estrutura:

ID MENU IDPAI

1 - Cadastros 0

2 - Consultas 0

4 - Pecas 1

5 - Produtos 1

6 - Vendas 2

1. No primeiro FOR insiro o pai Cadastros;

2. Vou para o segundo FOR, vou verificar os próximos itens (ou seja, a partir de Consultas), pra ver qual tem o IDPai igual ao ID;

3. Passa-se pelo Consultas e vai para o próximo item;

4. Quando chegar em Peças, vou adicionar ao meu menu.Items[menu.Items.Count - 1].ChildItems. Como o Cadastros é meu primeiro item, de índice zero, vai inserir o Peças no Cadastros;

5. Vou para o item Produtos, onde vai acontecer a mesma coisa;

6. Verifico o Vendas e passo para o próximo item;

7. Saio do segundo FOR e vou para o primeiro FOR;

8. Encontro o item Consultas, que é pai e vai ser inserido no menu;

9. Passo por Peças e Produtos, pois não batem a IDPai com a ID do menu Consultas;

10. Quando chegar no Vendas vou inserí-lo no menu.Items[menu.Items.Count -1].ChildItems. menu.Items.Count vai retornar 2. Menos 1, vai para o índice 1 que é o Consultas (o índice zero é o Cadastros).

Foi esse o passo a passo montado :) Acho que deve funcionar sim.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



  • Forum Statistics

    • Total Topics
      152.2k
    • Total Posts
      652k
×
×
  • Create New...