Search code examples
c#asp.netwebformsdropdowncascadingdropdown

Remember Cascading Dropdown value when navigating away from page


I maintain an application for my organization that uses Web Forms. I have to add cascading dropdowns and I need to have those dropdowns remember their values when I navigate away from the page. My first dropdown remembers its value but its cascading dropdown does not retain its value when I navigate back. Any suggestions?

Below are my dropdowns:

 <asp:UpdatePanel ID="updatePanel1" runat="server">
    <ContentTemplate><div class="dropDownSelection">
      <asp:DropDownList CssClass="topicDropDown" ID="topic1" DataTextField="NAME" DataValueField="ID" OnSelectedIndexChanged="Load_Section1" AutoPostBack="True" AppendDataBoundItems="true" runat="server"/>
      <asp:DropDownList CssClass="sectionDropDown" ID="section1" DataTextField="NAME" DataValueFile="ID" AutoPostBack="True" runat="server">
        <asp:ListItem Text="--- Select Section ---" Value="0"></asp:ListItem>
         </asp:DropDownList></div><br/>
    </ContentTemplate>
 </asp:UpdatePanel>

Below are the methods that load the dropdown values:

protected void Load_Topic1()
    {
        var topicStore = new TopicStore();

        var topics = topicStore.ReadTopics();

        foreach (var topic in topics)
        {
            var topicListItem = new ListItem(topic.Name, topic.Id.ToString());
            topic1.Items.Add(topicListItem);
            //topic1.Attributes.Add("Title", topic.Description);//only shows description for item at the bottom of the dropdown
        }

        topic1.Items.Insert(0, new ListItem("--- Select Topic ---", "0"));
    }

    protected void Load_Section1(object sender, EventArgs e)
    {
        section1.Items.Clear();

        var sectionStore = new SectionStore();

        var sections = sectionStore.ReadForTopic(Guid.Parse(topic1.SelectedValue));

        foreach (var section in sections)
        {
            var sectionListItem = new ListItem(section.Name, section.Id.ToString());
            section1.Items.Add(sectionListItem);
        }

        section1.Items.Insert(0, new ListItem("--- Select Section ---", "0"));
    }

Load_Topic1 is called on page load. The values of the dropdowns are stored in session when you navigate away from the page.

Below is how I load the values into session:

if (Session["Page"] != null)
{
    if (Session["SubmittedPayment"] != null)
    {
        //shazbot -- they've already hit submit
        Server.Transfer("default.aspx?logout=true");
    }
   topic1.SelectedValue = Session["topic1"] as string;
  section1.SelectedValue = Session["section1"] as string;
  rating1DropDown.SelectedValue = Session["rating1DropDown"] as string; 

    if (Session["Page"].ToString() == "HighSchoolInformation2.aspx")
    {
        Session.Add("Page", "InterestSurvey.aspx");
    }
    else if (Session["Page"].ToString() == "Payment.aspx" || Session["Page"].ToString() == "InterestSurvey.aspx")
    {
        Session.Add("Page", "InterestSurvey.aspx");
    }
  else 
  {
      topic1.SelectedValue = Session["topic1"] as string;
      section1.SelectedValue = Session["section1"] as string;
      rating1DropDown.SelectedValue = Session["rating1DropDown"] as string;
      Response.Redirect(Session["Page"].ToString());
   } 
}
   else
    {
    //they're not logged in, send them back to log in
    Server.Transfer("Default.aspx?logout=true");
    } 

In the code behind I load session variables like this:

protected void next_Click(object sender, EventArgs e)
    {
        Session.Add("topic1", topic1.SelectedValue);
        Session.Add("section1", section1.SelectedValue);
        Session.Add("rating1DropDown", rating1DropDown.SelectedValue);

        Page.Validate();
        if (Page.IsValid)
        {
            ModLangRequired.Visible = false;

            if (!checkModLang())
            {
                Response.Redirect("Payment.aspx");
            }
        }
    }

Like I said up top I inherited this code and I don't have the time for a complete rewrite at the moment.


Solution

  • Start by changing Load_Section1 as follows. Notice how we are using Guid.TryParse to conditionally load sections if a topic is selected.

    protected void Load_Section1()
    {
        section1.Items.Clear();
    
        section1.Items.Add(new ListItem("--- Select Section ---", "0"));
    
        Guid topicId;
        if (Guid.TryParse(topic1.SelectedValue, out topicId))
        {
            var sectionStore = new SectionStore();
    
            var sections = sectionStore.ReadForTopic(topicId);
    
            foreach (var section in sections)
            {
                var sectionListItem = new ListItem(section.Name, section.Id.ToString());
                section1.Items.Add(sectionListItem);
            }
        }
    }
    

    Then add a new event handler as follows:

    protected void TopicDropDown_OnSelectedIndexChanged(object sender, EventArgs e)
    {
        Load_Section1();
    }
    

    Now associate the OnSelectedIndexChanged event to the new handler:

    <asp:DropDownList ID="topic1" ... OnSelectedIndexChanged="TopicDropDown_OnSelectedIndexChanged" ... />
    

    Now you can restore the the page state as follows:

    if (Session["Page"] != null)
    {
        if (Session["SubmittedPayment"] != null)
        {
            //shazbot -- they've already hit submit
            Server.Transfer("default.aspx?logout=true");
        }
    
        Load_Topic1();
        topic1.SelectedValue = IsPostBack ? Request.Form[topic1.UniqueID] : (string)Session["topic1"];
        Load_Section1();
        section1.SelectedValue = IsPostBack ? Request.Form[section1.UniqueID] : (string)Session["section1"];
        Load_Rating1DropDown(); // not sure if you need this???
        rating1DropDown.SelectedValue = IsPostBack ? Request.Form[rating1DropDown.UniqueID] : (string)Session["rating1DropDown"];   
    
        if (Session["Page"].ToString() == "HighSchoolInformation2.aspx")
        {
            Session.Add("Page", "InterestSurvey.aspx");
        }
        else if (Session["Page"].ToString() == "Payment.aspx" || Session["Page"].ToString() == "InterestSurvey.aspx")
        {
            Session.Add("Page", "InterestSurvey.aspx");
        }
        else 
        {
            // you don't actually need to set values before you redirect
            Response.Redirect(Session["Page"].ToString());
        } 
    }
    else
    {
        //they're not logged in, send them back to log in
        Server.Transfer("Default.aspx?logout=true");
    }
    

    My assumption is the above code is called from Page_Load. Avoid making any extra calls to Load_Topic1 as well.