Question

I'm trying to access Controls in div but I can't find them.

I got a div with some controls in it.

<div id="divChampsFiltrageProjetsTest" class="divChampsFiltrageProjetsTest" runat="server">

  <span runat="server" style="color:black;"> Filtre 1 : </span>
  <asp:DropDownList ID="ddlFiltreProjets1" runat="server" ForeColor="Black" >
    <asp:ListItem Value="no" Selected="True">No. Projet</asp:ListItem>
    <asp:ListItem Value="desi">Designation Projet</asp:ListItem>
    <asp:ListItem Value="chef">Chef de Projet</asp:ListItem>
  </asp:DropDownList>

  <asp:TextBox ID="txtValeurFiltreProjets1" runat="server" ForeColor="Black" />

  <asp:Button ID="btnAddFiltre1" runat="server" Text="Ok" OnClick="btnAppliquerFiltreProjets_Click"/>

</div>

I can find these controls in the code behind. But the problem comes when I add some controls from code behind.

            HtmlGenericControl span = new HtmlGenericControl("span");
            DropDownList ddlList = new DropDownList();
            TextBox txtValeur = new TextBox();
            Button btnAdd = new Button();
            ListItem item1 = new ListItem("No. Projet", "no");
            ListItem item2 = new ListItem("Désignation Projet", "desi");
            ListItem item3 = new ListItem("Chef de Projets", "chef");

            span.Style.Add(HtmlTextWriterStyle.Color, "Black");
            span.InnerText = "Filtre " + (i + 1).ToString() + " : ";

            ddlList.ID = "ddlFiltreProjets" + (i + 1).ToString();
            ddlList.Items.Add(item1);
            ddlList.Items.Add(item2);
            ddlList.Items.Add(item3);

            txtValeur.ID = "txtValeurFiltreProjets" + (i + 1).ToString();
            txtValeur.ForeColor = System.Drawing.Color.Black;

            btnAdd = btnAddFiltre1;

            divChampsFiltrageProjetsTest.Controls.Add(span);
            divChampsFiltrageProjetsTest.Controls.Add(ddlList);
            divChampsFiltrageProjetsTest.Controls.Add(txtValeur);
            divChampsFiltrageProjetsTest.Controls.Add(btnAdd);

This part of the code add the controls to the div and when I got the page, controls are in the source code.

        <div id="MainContent_divChampsFiltrageProjets" class="divChampsFiltrageProjets" style="display:block;">
            <div id="MainContent_divChampsFiltrageProjetsTest" class="divChampsFiltrageProjetsTest">

                <span style="color:black;"> Filtre 1 : </span>
                <select name="ctl00$MainContent$ddlFiltreProjets1" id="MainContent_ddlFiltreProjets1" style="color:Black;">
<option value="no">No. Projet</option>
<option value="desi">Designation Projet</option>
<option selected="selected" value="chef">Chef de Projet</option>

</select>

                <input name="ctl00$MainContent$txtValeurFiltreProjets1" type="text" value="johan" id="MainContent_txtValeurFiltreProjets1" style="color:Black;" />

            <span style="color:Black;">Filtre 2 : </span><select name="ctl00$MainContent$ddlFiltreProjets2" id="MainContent_ddlFiltreProjets2">
<option value="no">No. Projet</option>
<option value="desi">D&#233;signation Projet</option>
<option value="chef">Chef de Projets</option>

</select><input name="ctl00$MainContent$txtValeurFiltreProjets2" type="text" id="MainContent_txtValeurFiltreProjets2" style="color:Black;" /><input type="submit" name="ctl00$MainContent$btnAddFiltre1" value="Ok" id="MainContent_btnAddFiltre1" /></div>

But when I try to get the controls that I add from code behind it says that the value is null.

    for (int i = 1; i < Convert.ToInt32(Session["nbFiltres"].ToString()) + 1; i++)
    {

        DropDownList ddl = (DropDownList)divChampsFiltrageProjetsTest.FindControl("ddlFiltreProjets"+i.ToString());
        TextBox txt = (TextBox)divChampsFiltrageProjetsTest.FindControl("txtValeurFiltreProjets" +i.ToString());

        Session["typeFiltreProjets" + i.ToString()] = ddl.SelectedValue.ToString();
        Session["valeurFiltreProjets" + i.ToString()] = txt.Text;
    }

This part is in the click event fonction of a button.

So my problem is that the controls that I add from code behind are not really in the div.

Is anyone know why?

Was it helpful?

Solution

When adding controls dynamically you will need to make sure that these are re-created after each post back.

There is a difference between declaring controls in the .aspx file and adding them programmatically from code behind:

When the controls are added declaratively then all the controls are there on future postbacks, because on every postback request ASP.NET Webforms recreates the state of the page using the declarations in the designer and the data from the Viewstate and from the posted form.

When the controls are addded programmatically then ASP.NET will try to do the same: recreate the state of the page on the server using the declarations in the .aspx file + ViewState + posted form. It does not have a way of knowing that you've modified the Controls hierarchy and that you've added or removed some controls, because these changes are not tracked in any way between postbacks. That is why you will need to recreate the expected hierarchy on every postback.

You will need to re-run your code that adds controls on the Page_Init event. This is important, because after this event ASP.NET will try to bind state information from the ViewState and from the posted data to the control hierarchy, that now will contain your dynamic controls. If you don't do this, you will still have your controls but you won't be able to retrieve the data posted by the user on those controls.

Here is how your code could look like:

public void Page_Init(object sender, EventArgs e){
    CreateDynamicControls();
}

public void CreateDynamicControls(){
    HtmlGenericControl span = new HtmlGenericControl("span");
    DropDownList ddlList = new DropDownList();
    TextBox txtValeur = new TextBox();
    Button btnAdd = new Button();
    ListItem item1 = new ListItem("No. Projet", "no");
    ListItem item2 = new ListItem("Désignation Projet", "desi");
    ListItem item3 = new ListItem("Chef de Projets", "chef");

    span.Style.Add(HtmlTextWriterStyle.Color, "Black");
    span.InnerText = "Filtre " + (i + 1).ToString() + " : ";

    ddlList.ID = "ddlFiltreProjets" + (i + 1).ToString();
    ddlList.Items.Add(item1);
    ddlList.Items.Add(item2);
    ddlList.Items.Add(item3);

    txtValeur.ID = "txtValeurFiltreProjets" + (i + 1).ToString();
    txtValeur.ForeColor = System.Drawing.Color.Black;

    btnAdd = btnAddFiltre1;

    divChampsFiltrageProjetsTest.Controls.Add(span);
    divChampsFiltrageProjetsTest.Controls.Add(ddlList);
    divChampsFiltrageProjetsTest.Controls.Add(txtValeur);
    divChampsFiltrageProjetsTest.Controls.Add(btnAdd);
}

You can find more info on MSDN, on the ASP.NET Page Life Cycle article.

OTHER TIPS

The divChampsFiltrageProjetsTest.Controls[3 * i]; doesn't look right perhaps you should try FindControl instead

for (int i = 1; i < Convert.ToInt32(Session["nbFiltres"].ToString()) + 1; i++)
    {

        DropDownList ddl = (DropDownList)divChampsFiltrageProjetsTest.FindControl("ddlFiltreProjets" + (i + 3 * i).ToString());
        TextBox txt = (TextBox)divChampsFiltrageProjetsTest.FindControl("txtValeurFiltreProjets" + (5 * i).toString());

        Session["typeFiltreProjets" + i.ToString()] = ddl.SelectedValue.ToString();
        Session["valeurFiltreProjets" + i.ToString()] = txt.Text;
    }

What you could do is have the

    HtmlGenericControl span = new HtmlGenericControl("span");
    DropDownList ddlList = new DropDownList();
    TextBox txtValeur = new TextBox();
    Button btnAdd = new Button();
    ListItem item1 = new ListItem("No. Projet", "no");
    ListItem item2 = new ListItem("Désignation Projet", "desi");
    ListItem item3 = new ListItem("Chef de Projets", "chef");

declared as fields in the Page class then add them on the page load providing the page is not postback;

public override void OnLoad(../*cant' remember the parameters*/){
    if(!Page.IsPostBack){
       span.Style.Add(HtmlTextWriterStyle.Color, "Black");

        span.InnerText = "Filtre " + (i + 1).ToString() + " : ";

        ddlList.ID = "ddlFiltreProjets" + (i + 1).ToString();
        ddlList.Items.Add(item1);
        ddlList.Items.Add(item2);
        ddlList.Items.Add(item3);

        txtValeur.ID = "txtValeurFiltreProjets" + (i + 1).ToString();
        txtValeur.ForeColor = System.Drawing.Color.Black;

        btnAdd = btnAddFiltre1;

        divChampsFiltrageProjetsTest.Controls.Add(span);
        divChampsFiltrageProjetsTest.Controls.Add(ddlList);
        divChampsFiltrageProjetsTest.Controls.Add(txtValeur);
        divChampsFiltrageProjetsTest.Controls.Add(btnAdd);

Then you should be able to just use them in your click event

for (int i = 1; i < Convert.ToInt32(Session["nbFiltres"].ToString()) + 1; i++)
{

    Session["typeFiltreProjets" + i.ToString()] = ddlList.SelectedValue.ToString();
    Session["valeurFiltreProjets" + i.ToString()] = txtValeur.Text;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top