Montando em ASP.NET uma estrutura com listas não ordenadas HTML dinamicamente

As tags HTML <UL><LI>…</LI></UL> são denominadas com listas não ordenadas, esta estrutura é comumente utilizada por diversos menus que utilizam a biblioteca Javascript  – Jquery.

Neste artigo utilizarei uma base de dados SQL Server, com estrutura básica de um menu com  hierarquia infinita. A figura 1 ilustra a estrutura da tabela denominada “Menu”, veja a descrição dos campos:

CodItemMenu – Chave primária da tabela e possui o código único de cada item;

Nome – Nome de exibição do Menu;

CodMenuPai – É o campo que vincula o item com outro do menu. Se esse campo não for preenchido, possui valor nulo (NULL) ele será considerado um “Menu Pai” que possuirá ou não filhos.

OrdemExibir – O campo será preenchido com um valor inteiro que irá definir a ordem de exibição nos itens do menu.

Figura 1 - Estrutura da tabela

Para simularmos um menu, esta tabela foi populada com os dados ilustrados na figura 2.

Figura 2 - Tabela Populada

Os itens que possuem o campo “CodMenuPai” nulo serão considerados estruturas da raiz, os que possuem algum valor serão “filhos” dos menus vinculados. A ordem de exibição obedecerá a ordem definida na coluna “OrdemExibir”.

A conexão com o banco de dados será feita “na mão”. A criação dinâmica é feita por duas funções chamadas por uma sub-rotina. A estrutura montada por essas funções serão exibidas em controle ASP.NET Literal. As funções que utilizei são: MontaMenu(), PossuiFilho() e MontaFilhos(). Segue a descrição de cada uma delas:

Sub-rotina que monta a String do menu e armazena em um literal.

public void MontaMenu()
          {
                  //Recuperar os Dados apenas dos 'menus pai' para armazena-los em uma DataTable
                  DataTable RetDados = null;
                   using (SqlConnection Conn = new SqlConnection(ConfigurationManager.ConnectionStrings["CsMenu"].ConnectionString)) {
                           const string SQL = "Select CodItemMenu,Nome from Menu where CodMenuPai is NULL order by OrdemExibir";
                           SqlCommand cmd = new SqlCommand(SQL, Conn);
                           SqlDataAdapter daConsulta = new SqlDataAdapter(cmd);
                           DataSet dsConsulta = new DataSet();
                           daConsulta.Fill(dsConsulta);
                           RetDados = dsConsulta.Tables[0];
                           Conn.Close();
                  }
                  //Criar a estrutura de lista não ordenadas html em uma String
                  string HTMLMenu = " <ul>";
                  if ((RetDados != null)) {
                           if (RetDados.Rows.Count > 0) {
                                    //Loop em todos os 'menus pai'
                                    for (int x = 0; x <= RetDados.Rows.Count - 1; x++) {
                                             int CodMenu = Convert.ToInt32(RetDados.Rows[x]["CodItemMenu"]);
                                             //Cria a estrutura de lista, que pode ser referenciada para um link ou não, neste exemplo estamos utilizando um link para a pagina default
                                             //e passando o codigo do menu numa querystring para ser trabalhado posteriormente
                                             HTMLMenu = HTMLMenu + "<li><a href='default.aspx?CodItemMenu=" + RetDados.Rows[x]["CodItemMenu"].ToString() + "'>" + RetDados.Rows[x]["Nome"].ToString() + "</a>";
                                             //Chama a função que verifica se o menu possui algum filho, essa funcao retorna verdadeiro ou falso
                                             if (PossuiFilho(CodMenu)) {
                                                      //Se o menu possui filho, chama a funcao que monta os filhos que retorna uma string do HTML
                                                     HTMLMenu = HTMLMenu + MontaFilhos(CodMenu);
                                                     //finaliza a tag do 'pai' do menu
                                                     HTMLMenu = HTMLMenu + "</ul>";
                                             } else {
                                                     //se nao possui filhos fecha a tag do item do menu
                                                     HTMLMenu = HTMLMenu + "</li>";
                                             }

                                    }

                           }
                  }
         //Popula o Literal com a String do HTML
                  LtrMenu.Text = HTMLMenu + "</ul>";
          }

Função que verifica se o menu possui filhos, retornando verdadeiro ou falso:

         public bool PossuiFilho(int CodItemMenu)
         {
                 //Recuperar os Dados se possui filhos e armazena-los em uma DataTable
                 DataTable RetDados = null;
                 bool Retorno = false;
                  using (SqlConnection Conn = new SqlConnection(ConfigurationManager.ConnectionStrings["CsMenu"].ConnectionString)) {
                          const string SQL = "Select Count(*) as TotalFilhos from Menu where CodMenuPai=@CodItemMenu";
                          SqlCommand cmd = new SqlCommand(SQL, Conn);
                          cmd.Parameters.AddWithValue("@CodItemMenu", CodItemMenu);
                          SqlDataAdapter daConsulta = new SqlDataAdapter(cmd);
                          DataSet dsConsulta = new DataSet();
                          daConsulta.Fill(dsConsulta);
                          RetDados = dsConsulta.Tables[0];
                          Conn.Close();
                 }
                 if (RetDados.Rows.Count > 0) {
                          //Se possuir filho retorna verdadeiro, senão falso
                          if (Convert.ToInt32(RetDados.Rows[0]["TotalFilhos"]) > 0) {
                                   Retorno = true;
                          } else {
                                   Retorno = false;
                          }
                 }
                  return Retorno;
         }

Função que monta os menus filho e retorna a String do HTML.

         public string MontaFilhos(int CodMenuPai)
         {
                 //Recuperar os Dados apenas dos 'menus filho' e armazena-los em uma DataTable
                 DataTable RetDados = null;
                 bool Retorno = false;
                  using (SqlConnection Conn = new SqlConnection(ConfigurationManager.ConnectionStrings["CsMenu"].ConnectionString)) {
                          const string SQL = "Select CodItemMenu,Nome  from Menu where CodMenuPai=@CodItemMenu order by OrdemExibir";
                          SqlCommand cmd = new SqlCommand(SQL, Conn);
                          cmd.Parameters.AddWithValue("@CodItemMenu", CodMenuPai);
                          SqlDataAdapter daConsulta = new SqlDataAdapter(cmd);
                          DataSet dsConsulta = new DataSet();
                          daConsulta.Fill(dsConsulta);
                          RetDados = dsConsulta.Tables[0];
                          Conn.Close();
                 }
                 string HTMLMenu = "";
                 //cria a estrutura HTML da lista
                 HTMLMenu = HTMLMenu + "<ul>";
                 if (RetDados.Rows.Count > 0) {
                          //Loop nos filhos do menu pai passado por parametro pela classe
                          for (int x = 0; x <= RetDados.Rows.Count - 1; x++) {
                                   int CodItemMenu = Convert.ToInt32(RetDados.Rows[x]["CodItemMenu"]);
                                   //Cria a estrutura de lista, que pode ser referenciada para um link ou não, neste exemplo estamos utilizando um link para a pagina default
                                   //e passando o codigo do menu numa querystring para ser trabalhado posteriormente
                                   HTMLMenu = HTMLMenu + "<li><a href='default.aspx?CodItemMenu=" + RetDados.Rows[x]["CodItemMenu"].ToString() + "'>" + RetDados.Rows[x]["Nome"].ToString() + "</a>";
                                   //verifica se esse menu possui filho e faz a recursividade nessa mesma classe
                                   if (PossuiFilho(CodItemMenu)) {
                                            //se possui filho chama novamente esta classe
                                            HTMLMenu = HTMLMenu + MontaFilhos(CodItemMenu);
                                            HTMLMenu = HTMLMenu + "</ul>";
                                   } else {
                                            //se nao possui filhos fecha a tag do item do menu
                                            HTMLMenu = HTMLMenu + "</li>";
                                   }
                          }

                 }
                 //Retorna a String do item do menu
                 return HTMLMenu;
         }

Veja o resultado exibido no navegador na figura 3.

Figura 3 - exibindo no navegador

Se você possuir um menu baseado em JQuery que utiliza essa estrutura de listas basta adicionar as referencias de estilo e JavaScript para adicionar nas tags criadas pelas classes o atributo do css. Existem vários modelos disponíveis na internet, utilize o que preferir!

Abaixo forneço o código em C# utilizando .NET Framework 4.0 e a base de dados para download. Não esqueça de alterar a ConnectionString!

Faça o Download do Projeto e do BD

Anúncios

Solução em uma linha – Pegar o último dia do mês anterior

Em VB.NET:

Dim UltimoDiaMesAnterior As Date = (Convert.ToDateTime("01/" + Now.Date.AddMonths(-1).ToString("MM/yyyy"))).AddMonths(1).AddDays(-1)

Em C#:

System.DateTime UltimoDiaMesAnterior = (Convert.ToDateTime("01/" + DateAndTime.Now.Date.AddMonths(-1).ToString("MM/yyyy"))).AddMonths(1).AddDays(-1);

DropDownList + SqlDataSource com campo “Selecione”

Esta dica rápida serve para resolver de uma maneira trivial problemas de quando o DropDownList conectado a um SqlDataSource precisa estar com a opção “Selecione” selecionada por padrão, sem que seja necessário programar nenhuma linha.

Na sua Select faça um UNION com uma Select simples que traga NULL e o texto de exibição … Isso resolve também os problemas quando os campos DropDownList dentro de FormView’s ou DetailsView’s, por exemplo, não tenham valores no momento do DataBind.

Segue exemplo de uma Select que resolve o problema:

SELECT NULL AS CodigoCidade, ‘– Selecione a Cidade –‘ as Nome

UNION

SELECT CodigoCidade, Nome FROM Cidades

Existem outras soluções, mas essa é a mais rápida e prática que conheço!