Criação de controles dinâmicos em .NET

Posted by Leticia Verta | Posted in .NET, C#, Geral | Posted on 18-12-2009-05-2008

2

Eis uma coisa que sempre encafifava minhas idéias: criação de controles dinâmicos no .NET.
Parece simples, porém, devido ao ‘complexo’ ciclo de vida das páginas da linguagem, se torna um pouco mais chatinho.
Vamos para o exemplo … que eu usei ainda hoje, diga-se de passagem :P

Criaremos uma página com um Panel e um Button

<!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>Relaxos - Controles Dinâmicos</title>
  </head>
  <body>
    <form id="form1" runat="server">
    <div>
      <asp:Panel ID="pnlTeste" runat="server" />
      <asp:Button ID="btnExibir" runat="server" Text="Botãozar" onclick="btnExibir_Click" />
    </div>
    </form>
  </body>
</html>

Agora criaremos, em tempo de execução, um TextBox e um Button – e seu respectivo evento. Exibiremos o conteúdo dos controles já adicionados através do btnExibir (notem que eu já setei um evento ao botão).

private TextBox txtDinamico;
private Button btnDinamico;
 
protected void Page_Load(object sender, EventArgs e)
{
  CriarControles();
}
 
private void CriarControles()
{
  txtDinamico = new TextBox();
  pnlTeste.Controls.Add(txtDinamico);
 
  btnDinamico = new Button();
  btnDinamico.Text = "+";
  btnDinamico.Click += new EventHandler(Adicionar);
  pnlTeste.Controls.Add(btnDinamico);
}
 
void Adicionar(object sender, EventArgs e)
{
  CriarControles();
}
 
protected void btnExibir_Click(object sender, EventArgs e)
{
  StringBuilder stbConteudo = new StringBuilder();
 
  //Pegamos todos os controles do pnlTeste
  foreach (Control oControl in pnlTeste.Controls)
  {
    //E filtramos para pegar os valores apenas dos TextBox's
    if (oControl.GetType().Name == "TextBox")
      stbConteudo.Append(String.Concat("\\nControle -> ", ((TextBox)oControl).UniqueID, " - ", ((TextBox)oControl).Text));
  }
 
  Response.Write(String.Concat("alert('" , stbConteudo.ToString(), "');"));
}

Rodando (ma oe) o projeto agora, vocês verão que os controles se perdem forever. A cada PostBack os controles somem, é como se nunca tivesse sido incluso nada ali. Isso acontece porque apenas as propriedades desses controles são serializadas, o controle em si não é, ou seja, teremos que persistir esses controles na raça … então let’s go:

public partial class ControlesDinamicos : System.Web.UI.Page
{
    private TextBox txtDinamico;
    private Button btnDinamico;
    private int qtde 
    {
        get { return Session["qtde"] == null ? 0 : Convert.ToInt32(Session["qtde"]); }
        set { Session["qtde"] = value; }
    }
    private int indice = 0;
 
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
            //Cria o primeiro controle
            CriarControles(false);
        else
        {
            //Mantém controles posteriormente criados
            for (int c = 0; c < qtde; c++)
                CriarControles(true);
        }
    }
 
    private void CriarControles(bool Persistencia)
    {
        txtDinamico = new TextBox();
        txtDinamico.ID = String.Concat("txtDinamico", indice);
        pnlTeste.Controls.Add(txtDinamico);
 
        btnDinamico = new Button();
        btnDinamico.Text = "+";
        btnDinamico.ID = String.Concat("btnDinamico", indice);
        btnDinamico.Click += new EventHandler(Adicionar);
        pnlTeste.Controls.Add(btnDinamico);
 
        indice++;
 
        if (!Persistencia)
            qtde++;
    }
 
    void Adicionar(object sender, EventArgs e)
    {
        CriarControles(false);
    }
 
    protected void btnExibir_Click(object sender, EventArgs e)
    {
        StringBuilder stbConteudo = new StringBuilder();
 
        //Pegamos todos os controles do pnlTeste
        foreach (Control oControl in pnlTeste.Controls)
        {
            //E filtramos para pegar os valores apenas dos TextBox's
            if (oControl.GetType().Name == "TextBox")
                stbConteudo.Append(String.Concat("\\nControle -> ", ((TextBox)oControl).UniqueID, " - ", ((TextBox)oControl).Text));
        }
 
        Response.Write(String.Concat("<script>alert('" , stbConteudo.ToString(), "');</script>"));
    }
}

No código acima, quando acontece a persistência (que nada mais é a recriação de novos controles), os controles mudam os ids (Ex.: existem os controles ctl01, ctl02 … PostBack … na recriação serão ctl03, ctl04, por ai vai) e mais uma vez, cadê os dados?? Pra evitar essa bagunça, setamos a identidade de cada controle e VUALÁ! :)

Bom, agora é só colocar um ajaxzinho pra ficar biito e adequar às necessidades diárias … quem quiser o código, só clicar.

[]’s

Leticia Verta, desenvolvedora aspirante em .NET rs