Search code examples
c#asp.netdynamic-usercontrols

DropDownList in User Control loses SelectedValue on first postback when loaded dynamically


I have an ASPX page that has a PlaceHolder in which User Controls are loaded dynamically. HTML markup is as follows:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Test.aspx.cs" Inherits="Test" %>

<!DOCTYPE html>

<html>
<head runat="server">
</head>
<body>
    <form id="form1" runat="server">

        <asp:Button ID="btnNumbers" Text="Select Numbers" OnClick="SelectNumbers" runat="server" />
        <br /><br />
        <asp:Button ID="btnLetters" Text="Select Letters" OnClick="SelectLetters" runat="server" />
        <br /><br />

        <asp:PlaceHolder ID="phContent" runat="server" />

    </form>
</body>
</html>

The Code Behind is as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;


public partial class Test : System.Web.UI.Page
{
    protected void Page_Init(object sender, EventArgs e)
    {
        if (!IsPostBack)
            HttpContext.Current.Session["control"] = "~/Controls/Numbers.ascx";
        LoadControl();        
    }

    protected void SelectNumbers(object sender, EventArgs e)
    {
        HttpContext.Current.Session["control"] = "~/Controls/Numbers.ascx";
        LoadControl();
    }

    protected void SelectLetters(object sender, EventArgs e)
    {
        HttpContext.Current.Session["control"] = "~/Controls/Letters.ascx";
        LoadControl();
    }

    private void LoadControl()
    {
        phContent.Controls.Clear();
        var control = Page.LoadControl((String)HttpContext.Current.Session["control"]);
        phContent.Controls.Add(control);
    }
}

The first user control has a DropDownList to select numbers. It has markup as follows:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Numbers.ascx.cs" Inherits="Numbers" %>


<asp:DropDownList ID="ddlSelectNumbers"
                  AutoPostBack="true" runat="server"
                  OnSelectedIndexChanged="SelectNumbers_IndexChanged" >
    <asp:ListItem Text="One" Value="1" />
    <asp:ListItem Text="Two" Value="2" />
    <asp:ListItem Text="Three" Value="3" />
</asp:DropDownList>

<br /><br />

<asp:Label ID="lblSelectedNumber" runat="server" />

And Code Behind as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
using Superexpert.Controls;


public partial class Numbers : System.Web.UI.UserControl
{
    public override String ID
    {
        get { return "Numbers"; }
        set { }
    }

    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected void SelectNumbers_IndexChanged(object sender, EventArgs e)
    {
        lblSelectedNumber.Text = ((DropDownList)sender).SelectedItem.Text;
    }
}

The second user control has a DropDownList to select letters. It has markup as follows:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Letters.ascx.cs" Inherits="Letters" %>



<asp:DropDownList ID="ddlSelectLetters"
                  AutoPostBack="true" runat="server"
                  OnSelectedIndexChanged="SelectLetters_IndexChanged" >
    <asp:ListItem Text="A" Value="a" />
    <asp:ListItem Text="B" Value="b" />
    <asp:ListItem Text="C" Value="c" />
</asp:DropDownList>

<br /><br />

<asp:Label ID="lblSelectedLetter" runat="server" />

And Code Behind as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
using Superexpert.Controls;


public partial class Letters : System.Web.UI.UserControl
{
    public override String ID
    {
        get { return "Letters"; }
        set { }
    }

    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected void SelectLetters_IndexChanged(object sender, EventArgs e)
    {
        lblSelectedLetter.Text = ((DropDownList)sender).SelectedItem.Text;
    }
}

Everything works find when the page first loads (!IsPostBack). You can select numbers from the DropDownList and it's SelectedItemChanged event fires, it's SelectedValue is updated, and the Label is updated.

The problem happens when you click one of the buttons to dynamically load one of the user controls. After that, the first time you select something from the DropDownList, the SelectedItemChanged event doesn't fire, it's SelectedValue is not updated, and therefore Label is not updated. Afterwards, everything works fine.

What is causing this to happen?

Thanks in advance!


Solution

  • You are very closed. You just need to assign ID to dynamically created control.

    Basically, you need to assign ID to dynamically created control, if you want to retrieve them on post back.

    Look at 3 <--- in the following code.

    public partial class Test : System.Web.UI.Page
    {
       ... Same as above
    
        private void LoadControl()
        {
            phContent.Controls.Clear();
            var control = Page.LoadControl((String)HttpContext.Current.Session["control"]);
            control.ID = "1"; <--- 1. Control ID is required. 
            phContent.Controls.Add(control);
        }
    }
    
    public partial class Numbers : System.Web.UI.UserControl
    {
        // public override String ID ... <--- 2. Remove this
    
        protected void SelectNumbers_IndexChanged(object sender, EventArgs e)
        {
            lblSelectedNumber.Text = ((DropDownList)sender).SelectedItem.Text;
        }
    }
    
    public partial class Letters : System.Web.UI.UserControl
    {
        // public override String ID ... <--- 3. Remove this
    
        protected void SelectLetters_IndexChanged(object sender, EventArgs e)
        {
            lblSelectedLetter.Text = ((DropDownList)sender).SelectedItem.Text;
        }
    }