ASP.NET / C#: DropDownList SelectedIndexChanged in server control not firing
Asked Answered
W

5

11

I'm creating a server control that basically binds two dropdown lists, one for country and one for state, and updates the state dropdown on the country's selectedindexchanged event. However, it's not posting back. Any ideas why? Bonus points for wrapping them in an UpdatePanel (having rendering issues; maybe because I don't have a Page to reference?)

Here's what I have (with some extra data access stuff stripped out):

public class StateProv : WebControl
{
    public string SelectedCountry;
    public string SelectedState;

    private DropDownList ddlCountries = new DropDownList();
    private DropDownList ddlStates = new DropDownList();

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        IList<Country> countries = GetCountryList();
        IList<State> states = new List<State>();

        if (SelectedCountry != null && SelectedCountry != "")
        {
            states = GetStateList(GetCountryByShortName(SelectedCountry).CountryShortName);
        }
        else
        {
            states.Add(new State { CountryId = 0, Id = 0, StateLabelName = "No states available", StateLongName = "No states available", StateShortName = "" });
        }

        ddlCountries.DataSource = countries;
        ddlCountries.DataTextField = "CountryLongName";
        ddlCountries.DataValueField = "CountryShortName";
        ddlCountries.SelectedIndexChanged += new EventHandler(ddlCountry_SelectedIndexChanged);
        ddlCountries.AutoPostBack = true;

        ddlStates.DataSource = states;
        ddlStates.DataTextField = "StateLongName";
        ddlStates.DataTextField = "StateShortName";

        ddlCountries.DataBind();
        ddlStates.DataBind();

        if (!string.IsNullOrEmpty(SelectedCountry))
        {
            ddlCountries.SelectedValue = SelectedCountry;

            if (!string.IsNullOrEmpty(SelectedState))
            {
                ddlStates.SelectedValue = SelectedState;
            }
        }            
    }


    protected override void RenderContents(HtmlTextWriter output)
    {
        ddlCountries.RenderControl(output);
        ddlStates.RenderControl(output);
    }

    private IList<Country> GetCountryList()
    {
        //return stuff
    }

    private IList<State> GetStateList(Country country)
    {
        //return stuff
    }

    private IList<State> GetStateList(string countryAbbrev)
    {
        Country country = GetCountryByShortName(countryAbbrev);
        return GetStateList(country);
    }

    private Country GetCountryByShortName(string countryAbbrev)
    {
        IList<Country> list = dataAccess.RetrieveQuery<Country>();
        //return stuff
    }

    private IList<State> GetAllStates()
    {
        //return stuff
    }

    protected void ddlCountry_SelectedIndexChanged(object sender, EventArgs e)
    {
        IList<State> states = GetStateList(GetCountryList()[((DropDownList)sender).SelectedIndex]);
        ddlStates.DataSource = states;
        ddlStates.DataBind();
    }
}

Edit: Viewstate is on the page, and other controls on the page perform postbacks correctly, just not this.

Wandawander answered 20/2, 2009 at 16:42 Comment(2)
Probably doesn't count as an answer but the Ajax Control Toolkit provides what you want already inside an update panel: asp.net/AJAX/AjaxControlToolkit/Samples/CascadingDropDown/…Natka
Yeah; I've sworn off the ACT forever, though. Absolute garbage IMO; I'm actually building a replacement for my project, since we could only get the CCD control to work with a web service, which had other implications.Wandawander
S
5

Is Viewstate turned on?

Edit: Perhaps you should reconsider overriding the rendering function

  protected override void RenderContents(HtmlTextWriter output)
    {
        ddlCountries.RenderControl(output);
        ddlStates.RenderControl(output);
    }

and instead add the dropdownlists to the control and render the control using the default RenderContents.

Edit: See the answer from Dennis which I alluded to in my previous comment:

Controls.Add ( ddlCountries );
Controls.Add ( ddlStates );
Soft answered 20/2, 2009 at 16:45 Comment(5)
This looks promising. If ViewState is off (on the dropdown or any of its parents - all the way up to the page) then the event won't fire. (It should post back though...)Tsimshian
Viewstate is on on the page that the control resides on. Is there something specific to this control, in this .cs file, that I need to do?Wandawander
a quick way to check is to look at the source code and see if anything is stored in viewstateSoft
Yeah; it's on for the page and other postback controls are working.Wandawander
You Saved my day :) and a free beer from me!Viscera
B
4

I can't see that you're adding these controls to the control hierarchy. Try:

Controls.Add ( ddlCountries );
Controls.Add ( ddlStates );

Events won't be invoked unless the control is part of the control hierarchy.

Bittencourt answered 20/2, 2009 at 17:30 Comment(4)
Yes - and do this in an event earlier than the Load (such as the Init); otherwise the controls won't be in the right place when the ViewState gets reloaded.Tsimshian
Yeah, or preferably in override CreateChildControlsBittencourt
Was about to say the same thing...they should be created and added to the Controls collection in CreateChildControls. You can drop the Render override then too.Illinois
Thanks! That was definitely it.Wandawander
O
3

You need to set AutoPostBack to true for the Country DropDownList.

protected override void OnLoad(EventArgs e)
{
    // base stuff

    ddlCountries.AutoPostBack = true;

    // other stuff
}

Edit

I missed that you had done this. In that case you need to check that ViewState is enabled.

Orcus answered 20/2, 2009 at 16:45 Comment(1)
Does his line "ddlCountries.AutoPostBack = true;" not do this?Soft
B
1

I had the same problem but got round it by setting AutoPostBack to true and in an update panel set the trigger to the dropdownlist control id and event name to SelectedIndexChanged e.g.

    <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Always" enableViewState="true">
        <Triggers>
            <asp:AsyncPostBackTrigger ControlID="ddl1" EventName="SelectedIndexChanged" />
        </Triggers>
        <ContentTemplate>
            <asp:DropDownList ID="ddl1" runat="server" ClientIDMode="Static" OnSelectedIndexChanged="ddl1_SelectedIndexChanged" AutoPostBack="true" ViewStateMode="Enabled">
                <asp:ListItem Text="--Please select a item--" Value="0" />
            </asp:DropDownList>
        </ContentTemplate>
    </asp:UpdatePanel>
Billups answered 14/11, 2011 at 12:48 Comment(0)
E
0

First, I would like to clarify something. Is this a post back (trip back to server) never occur, or is it the post back occurs, but it never gets into the ddlCountry_SelectedIndexChanged event handler?

I am not sure which case you are having, but if it is the second case, I can offer some suggestion. If it is the first case, then the following is FYI.

For the second case (event handler never fires even though request made), you may want to try the following suggestions:

  1. Query the Request.Params[ddlCountries.UniqueID] and see if it has value. If it has, manually fire the event handler.
  2. As long as view state is on, only bind the list data when it is not a post back.
  3. If view state has to be off, then put the list data bind in OnInit instead of OnLoad.

Beware that when calling Control.DataBind(), view state and post back information would no longer be available from the control. In the case of view state is on, between post back, values of the DropDownList would be kept intact (the list does not to be rebound). If you issue another DataBind in OnLoad, it would clear out its view state data, and the SelectedIndexChanged event would never be fired.

In the case of view state is turned off, you have no choice but to rebind the list every time. When a post back occurs, there are internal ASP.NET calls to populate the value from Request.Params to the appropriate controls, and I suspect happen at the time between OnInit and OnLoad. In this case, restoring the list values in OnInit will enable the system to fire events correctly.

Thanks for your time reading this, and welcome everyone to correct if I am wrong.

Electrograph answered 20/2, 2009 at 17:14 Comment(2)
It's not hitting the server at all when I change the selected list item. Thanks, though; that is another issue I've had to fix in other areas and it's good information.Wandawander
I see; then I think the answer from Dennis Myren will probably the correct one: the two DropDownList are not in the control tree, so even though they are correctly rendered, ASP.NET event handling mechanisms simply could not see the existance from the Page level, thus no event is fired.Electrograph

© 2022 - 2024 — McMap. All rights reserved.