Dynamically created cascading dropdown lists

2019-07-22 16:59发布

This issue might be trivial for some but for the life of me, I cannot seem to figure it out.

Setup: I have a dropdown (DropDownList1) added at design time. DropDownList1 dynamically creates other dropdowns (DDL1, DDL2, DDL3) at runtime based on the selected value. The dropdown list items is generated every postback as default values. Some of the dynamically created dropdowns (DLL2, DDL3) are also cascading dropdowns wherein DDL3 data items are generated based on DDL2 selected item. I have an onSelectedIndexChanged event on DDL2 to generate data items for DDL3.

Problem: DDL1 and DDL2 selected values are retained on postback, which makes sense since it is generated onpageload. DDL3 shows the correct data items based on the DDL2 selection, but upon selecting a value, the page posts back and loses the selected value.

Markup:

            <asp:UpdatePanel ID="upanel" runat="server">
                <ContentTemplate>
                    <div class="container1">
                        <div id="params-container" class="container">
                            <asp:DropDownList ID="DropDownList1" runat="server" CssClass="input-fields" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged" AutoPostBack="true"></asp:DropDownList>
                            <asp:PlaceHolder ID="DatesPh" runat="server" EnableViewState="false"></asp:PlaceHolder>
                            <asp:PlaceHolder ID="SeasonPh" runat="server" EnableViewState="false"></asp:PlaceHolder>
                            <asp:PlaceHolder ID="CompanyPh" runat="server" EnableViewState="false"></asp:PlaceHolder>
                            <asp:PlaceHolder ID="BrandPh" runat="server" EnableViewState="false"></asp:PlaceHolder>
                            <asp:PlaceHolder ID="LocationPh" runat="server" EnableViewState="false"></asp:PlaceHolder>
                            <asp:PlaceHolder ID="GenderPh" runat="server" EnableViewState="false"></asp:PlaceHolder>
                            <asp:PlaceHolder ID="LinePh" runat="server" EnableViewState="false"></asp:PlaceHolder>
                            <asp:PlaceHolder ID="SubLinePh" runat="server" EnableViewState="false"></asp:PlaceHolder>
                            <asp:PlaceHolder ID="PlaceHolder1" runat="server" EnableViewState="false"></asp:PlaceHolder>
                            <asp:Button ID="Button1" runat="server" Text="Show" OnClick="Button1_Click" class="input-button" />
                        </div>
                    </div>
                </ContentTemplate>
            </asp:UpdatePanel>

Code Behind:

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        using (SqlConnection cn = new SqlConnection(connStr))
        {
//This is my design time dropdown.
//List item is generated only on first request.
//It has AutoPostBack=true so that new controls will be created based on the selection.

            DropDownList1.DataSource =  GetSqlData("sp_getReports",null);
            DropDownList1.DataTextField = "ReportName";
            DropDownList1.DataValueField = "ReportNum";
            DropDownList1.DataBind();
            DropDownList1.Items.Insert(0, new ListItem("Select a report", ""));
            DropDownList1.SelectedIndex = 0;
        }
    }

//This is where I create all controls dynamically (some tb and some ddl).
//I am also generating the list items for the ddl here dynamically.  
//Everything happens on pageload.

using (SqlConnection con = new SqlConnection(connStr))
{

    using (SqlCommand cmd = new SqlCommand("sp_fieldTableMap", con))
    {
        DataTable dtable = new DataTable();
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@inputRpt", DropDownList1.SelectedValue);
        SqlDataAdapter adp = new SqlDataAdapter(cmd);
        adp.Fill(dtable);

        foreach (DataRow dr in dtable.Rows)
        {
            if (dr["SqlQuery"].ToString().Trim() == "")
            {
                TextBox tb = new TextBox();
                tb.ID = dr["AspId"].ToString().Trim();
                tb.CssClass = "input-fields";
                tb.Attributes.Add("placeholder", dr["FieldName"].ToString().Trim());

                Control chkPh = FindControl(dr["Container"].ToString().Trim());
                if (chkPh is PlaceHolder)
                {
                    PlaceHolder pHolder = chkPh as PlaceHolder;
                    pHolder.Controls.Add(tb);
                }
            }
            else
            {
                DropDownList ddl = new DropDownList();
                ddl.ID = dr["AspId"].ToString().Trim();
                ddl.CssClass = "input-fields";
                ddl.AutoPostBack = true;

//I am dynamically creating the selectedindexchanged event
//for one of my ddl to provide cascading dropdown functionality on another dropdown.
                        if (ddl.ID == "brandCode")
                        {    
                ddl.SelectedIndexChanged += new EventHandler(brandCode_SelectedIndexChanged);
                        }
                        if (ddl.ID == "genderCode")
                        {
                            ddl.SelectedIndexChanged += new EventHandler(genderCode_SelectedIndexChanged);
                        } 
                Control chkPh = FindControl(dr["Container"].ToString().Trim());
                if (chkPh is PlaceHolder)
                {
                    PlaceHolder pHolder = chkPh as PlaceHolder;
                    pHolder.Controls.Add(ddl);
                }

                using (SqlConnection cn = new SqlConnection(connStr))
                {

//As I said, I generate the dropdown data items on pageload

                    DataTable sqlTab = new DataTable();
                    SqlCommand sqlCmd = new SqlCommand(dr["SqlQuery"].ToString().Trim(), cn);
                    sqlCmd.CommandType = CommandType.Text;
                    SqlDataAdapter sqlAdp = new SqlDataAdapter(sqlCmd);
                    sqlAdp.SelectCommand.CommandTimeout = 60;
                    sqlAdp.Fill(sqlTab);
                    ddl.DataSource = sqlTab;

                    ddl.DataTextField = dr["DdlText"].ToString().Trim();
                    ddl.DataValueField = dr["DdlValue"].ToString().Trim();
                    ddl.DataBind();
                    ddl.Items.Insert(0, new ListItem("", ""));

//Chidambaram's modified code added after databind of "DDL3"

                    if (ddl.ID == "genderCode") { ddl.SelectedValue = ddlValue; }

                }
            }
        }
    }
}
}
//End of pageload

public String ddlValue
{
    get
    {
        if (ViewState["ddlValue"] == null)
        {
            ViewState["ddlValue"] = String.Empty;
        }
        return ViewState["ddlValue"].ToString();
    }
    set
    {
        ViewState["ddlValue"] = value;
    }
}


//Also added an event for "DDL3" selectedindex to assign its value to the viewstate

    protected void genderCode_SelectedIndexChanged(object sender, EventArgs e)
    {
        Control chkGender = FindControl("genderCode");
        if (chkGender is DropDownList)
        {
            DropDownList ddlGender = chkGender as DropDownList;
            if (ddlGender.SelectedValue == "-1")
            {

            }
            else
            {
                ddlValue = ddlGender.SelectedValue;
            }
        }
    }


protected void brandCode_SelectedIndexChanged(object sender, EventArgs e)
{

//Cascading Dropdown: This event generates the data item of one dropdown based on its selection.
//This runs successfully, gender dropdown only displays the appropriate items based on the brand dropdown.

    Control chkBrand = FindControl("brandCode");
    if (chkBrand is DropDownList)
    {
        DropDownList ddlBrand = chkBrand as DropDownList;
        if (ddlBrand.SelectedValue == "-1")
        {
        }
        else
        {
            SqlParameter param = new SqlParameter();
            param.ParameterName = "@brandCode";
            param.Value = ddlBrand.SelectedValue;    
            Control chkGender = FindControl("genderCode");
            if (chkGender is DropDownList)
            {
                DropDownList ddlGender = chkGender as DropDownList;
                ddlGender.DataSource = GetSqlData("sp_getGender", param);
                ddlGender.DataBind();
                ddlGender.Items.Insert(0, new ListItem("", ""));
                ddlGender.SelectedIndex = 0;
            }
        }
    }
}

private DataSet GetSqlData(string SpName, SqlParameter SpParam)
{
    SqlConnection con = new SqlConnection(connStr);
    SqlDataAdapter da = new SqlDataAdapter(SpName, con);
    da.SelectCommand.CommandType = CommandType.StoredProcedure;
    if (SpParam != null)
    {
        da.SelectCommand.Parameters.Add(SpParam);
    }
    DataSet DS = new DataSet();
    da.Fill(DS);
    return DS;
}

Any help is greatly appreciated. Thanks.

Added some comments.

1条回答
We Are One
2楼-- · 2019-07-22 17:35

You can use the viewstate like below to set and get the value. once the value is utilized, then set it to empty or null.

 public String ddlValue
    {
        get
        {
            if (ViewState["ddlValue"] == null)
            {
                ViewState["ddlValue"] = String.Empty;
            }
            return ViewState["ddlValue"].ToString();
        }
        set
        {
            ViewState["ddlValue"] = value;
        }
    }

public void Page_Load(object sender, EventArgs e)
{
    if (this.ddlValue!=null)
    {
        //set the value here in ddl
        ddl3.selectedvalue=ddlValue;
    }
}
查看更多
登录 后发表回答