views:

119

answers:

2

I recently read this article on smart use of ViewState and am particularly interested in not having unnecessary static data in ViewState. However, I'm also curious if I can do the same thing for a parent-child dropdown, like the classic Country/CountrySubDivision example.

So I have this markup:

    <asp:DropDownList runat="server" ID="ddlCountry" DataTextField="Name" DataValueField="ID" EnableViewState="false" />
    <asp:DropDownList runat="server" ID="ddlCountrySubdivision" DataTextField="Name" DataValueField="ID" EnableViewState="false" />
    <asp:Button runat="server" ID="btnTest" />

And this codebehind:

    public class Country
    {
        public string Name { get; set;}
        public int Id { get; set; }
    }

    public class CountrySubdivision
    {
        public string Name { get; set; }
        public int Id { get; set; }
        public int CountryId { get; set; }
    }

    protected override void OnInit(EventArgs e)
    {
        var l = new List<Country>();
        l.Add(new Country { Name = "A", Id = 1 });
        l.Add(new Country { Name = "B", Id = 2 });
        l.Add(new Country { Name = "C", Id = 3 });
        ddlCountry.DataSource = l;
        ddlCountry.DataBind();

        var l2 = new List<CountrySubdivision>();
        l2.Add(new CountrySubdivision { Name = "A1", Id = 1, CountryId = 1 }); 
        l2.Add(new CountrySubdivision { Name = "A2", Id = 2, CountryId = 1 });
        l2.Add(new CountrySubdivision { Name = "B1", Id = 4, CountryId = 2 });
        l2.Add(new CountrySubdivision { Name = "B2", Id = 5, CountryId = 2 });
        l2.Add(new CountrySubdivision { Name = "C1", Id = 7, CountryId = 3 });
        l2.Add(new CountrySubdivision { Name = "C2", Id = 8, CountryId = 3 });

        // this does not work: always comes out 1 regardless of what's actually selected
        var selectedCountryId = string.IsNullOrEmpty(ddlCountry.SelectedValue) ? 1 : Int32.Parse(ddlCountry.SelectedValue);

        // this does work: 
        var selectedCountryIdFromFormValues = Request.Form["ddlCountry"];

        ddlCountrySubdivision.DataSource = l2.Where(x => x.CountryId == selectedCountryId).ToList();
        ddlCountrySubdivision.DataBind();

        base.OnInit(e);
    }

So the first thing I noticed is that even when EnableViewstate is false, my country control's value is persisted across requests with no extra effort. Sweet. That's a lot of serialized stuff I don't need to send across the wire on form submissions.

Then I came to the example above with a pair of parent-child drop downs, and I see that ddlCountry.SelectedValue is defaulting whereas Request.Form["ddlCountry"] is reflecting the control's value.

Is there a way to keep EnableViewState = "false" without resorting to Request.Form to get a dependent control's value?

+1  A: 

Then I came to the example above with a pair of parent-child drop downs, and I see that ddlCountry.SelectedValue is defaulting whereas Request.Form["ddlCountry"] is reflecting the control's value.

The reason you are seeing this behavior is that at that point in the page's lifecycle, Viewstate hasn't been loaded. When Viewstate is loaded, it is taken from the Request.Form object values, so you are seeing correct values there.

Gabriel McAdams
+1  A: 

Because of the ASP.NET Page Life Cycle

You'll have access to the newly selected value in the ddlCountry's OnSelectedIndexChanged method.

Request.Form["ddlCountry"] is the old school way (classic ASP) of getting the selected value, but if you are using WebForms, it's probably easier to just go with the flow of the page life cycle. I found WebForms a little weird initailly coming from classic ASP, but once you understand the Page Life Cycle, it's not so bad.

nickyt
Yeah, the point is that I do not want a big old list of 200 countries sent across the wire on every postback since it's really not necessary. We're currently using EnableViewState="true" and doing things in OnLoad.
Josh Kodroff
@Josh - why not use a pagemethod then? You can just pass back the selected value and then your dependent picklist can use that value to populate itself. Might mean you need to change your approach, but less stuff goes down the wire this way.
nickyt