Trabalhando com controles dinâmicos em ASP.NET

13:09 , 5 Comments

Um pequeno exemplo de como trabalhar com controles dinâmicos.
Para facilitar eu achei melhor não encher o código do comentário explicando linha por linha. Isto iria poluir muito, e no final não seria possível para entender nada. Vou descrever aqui a ideia básica do código e no final do post eu coloco um pequeno FAQ para esclarecer mais alguns detalhes.
Quando o usuário clica no botão "Adicionar" a aplicação adiciona um novo TextBox no Panel. Já quando o usuário clica em salvar eu imprimo os valores, para provar que os controles não estão perdendo valor.
Para fazer a coisa toda funcionar o segredo está em sempre re-adicionar os controles nos eventos Page_Load ou Page_Init. Uma vez que o usuário clicou em "Adicionar", não basta apenas criar o controle e esperar que no próximo PostBack ele esteja lá. Ele não estará.
No meu caso como só vou adicionar TextBox a única coisa que eu precisei fazer foi criar um campo HiddenField para guardar a quantidade de controles que eu já havia criado.
Em problemas mais complexos, onde existirá mais de um tipo de controle, ou o usuário poderá apagar os controles, será necessário guardar essas informações na ViewState. Nesse caso os controles devem ser recriados no evento Page_Load porque a ViewState ainda não existe no evento Page_Init
   <asp:Button ID="btnAddControle" runat="server" Text="Adicionar" OnClick="btnAddControle_Click" />
   <asp:Panel ID="pnlControles" runat="server">
   </asp:Panel>
   <asp:HiddenField ID="hdfQtdControles" runat="server" Value="0" />
   <asp:Button ID="btnSalvar" runat="server" Text="Salvar" OnClick="btnSalvar_Click1" />
   <br />
   <asp:Literal ID="ltlResultado" runat="server">

protected void Page_Init(object sender, EventArgs e)
{
    if (IsPostBack)
    {
        for (int i = 0; i < int.Parse(Request.Params[hdfQtdControles.ClientID.Replace("_", "$")].ToString()); i++)
        {
            
            TextBox txtControle = new TextBox()
            {
                ID = "txtControle" + pnlControles.Controls.Count
            };

            pnlControles.Controls.Add(txtControle);
        }
    }
}

protected void btnAddControle_Click(object sender, EventArgs e)
{
    TextBox txtControle = new TextBox()
    {
        ID = "txtControle" + pnlControles.Controls.Count
    };

    pnlControles.Controls.Add(txtControle);

    hdfQtdControles.Value = (pnlControles.Controls.Count - 1).ToString();
}

protected void btnSalvar_Click1(object sender, EventArgs e)
{
    ltlResultado.Text = "";
    foreach (var txtControle in pnlControles.Controls)
    {
        try
        {
            TextBox txtControleTextBox = (TextBox)txtControle;
            ltlResultado.Text += txtControleTextBox.ID + ": " + txtControleTextBox.Text + "
";
        }
        catch (System.InvalidCastException) { }
    }
}

A hora der um tempo prometo que faço o FAQ ;-).

Código Fonte: http://db.tt/ETpCOqKb

5 comentários:

Telles disse...

Samuel, boa tarde. finalmente achei um post sobre um problema que estou tentando resolver.
Copiei e colei seu codigo no meu VS2010.
Simplesmente não funcionou. Ele não mostra o numero ao Salvar.
Ao debugar, no init ele nao entra no FOR e na execução do foreach ele nao percorre os controles.
Pode me ajudar?
Existe alguma coisa que precisa ser configurado no VS?

Telles disse...
Este comentário foi removido por um administrador do blog.
Samuel Cazelli disse...

Telles pra mim está funcionando normal. Dá uma olhada nesse projeto.

http://db.tt/ETpCOqKb

Telles disse...

Oi Samuel,
realmente funcionou porem somente depois que tirei o for int.Parse(Request.Params[hdfQtdControles.ClientID.Replace("_", "$")].ToString()). Estranho não funcionar aqui.
Realmente o segredo é recriar o objeto no Init. Eu tenho um radioButtonList, que no momento de sua criação e ADD em um painel eu resolvi colocar em uma Session. Após o usuário escolher o valor do RadioButtonList e apertar um botao, realizando o postback, eu consigo pegar realmente o valor selecionado.
Uma pergunta: Poderia me explicar essa função int.Parse que colocou no seu codigo. Sou novato e ainda estou aprendendo :)
Abs

Samuel Cazelli disse...

Uma coisa que vocÊ deve atentar-se é que se o usuário tiver duas janelas aberta na mesma área, dependendo da forma que você grava na session você terá problemas de uma página alterando dados da outra.

O int.parse serve para converter uma string en int.

Não sei se eu entendi exatamente o seu cenário, mas se você tem um RadioButtomList com e os itens desse elemento são dinâmicos. Você não precisa usar a técnica que expliquei, você pode fazer direto através da propriedade itens do RadioButtomList.

Agora se você tem vários RadioButtomList que serão adicionados dinâmicos na página ai sim.