-1

I'm surprised at how difficult this question has been for me. I have a OnSelectedIndexChanged listener for a asp:DropDownList that fires correctly. I'm trying to assign the NEW selected value to a variable. However, inside my listener method, the "SelectedItem.Text" returns the DropDownList's value BEFORE the event was fired. Any insight on how to get the new value would be appreciated. Thanks.

---- EDIT ------ Below is the full code source

 public partial class About : Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        BuildTable();
        updateFilterPanel();
    }

    private void BuildTable()
    {
        ArrayList players = FilterHandler.getInstance().getFilteredPlayerList();
        List<Filter> filters = FilterHandler.getInstance().allFilters;

        StringBuilder html = new StringBuilder();
        html.Append("<table  id=\"tbl_listThisSeason\" class=\"table table-hover\">");
        html.Append("<thead class=\"thead-dark\"><tr><th scope=\"col\" > Name </th><th scope = \"col\" > Position </th><th scope=\"col\">Team</th>");

        foreach (Filter f in filters)
        { 
            if(!f.isPrimary())
                html.Append("<th scope=\"col\" >"+f.columnTitle+"</th>");
        }

            html.Append("</tr></thead><tbody>");

        foreach (JObject p in players)
        {
            html.Append("<tr>");
            html.Append("<td>" + (string)p["firstName"] + " " + (string)p["lastName"] + "</td>");
            html.Append("<td>" + (string)p["position"] + "</td>");
            html.Append("<td>" + CloudDataReceiver.getTeamName((string)p["teamId"]) + "</td>");
            foreach (Filter f in filters)
                html.Append("<td>" + (string)p[f.field] + "</td>");
            html.Append("</tr>");
        }

        html.Append("</tbody></table>");
        if (DataTable.Controls.Count > 0)
            DataTable.Controls.RemoveAt(0);
        DataTable.Controls.Add(new Literal { Text = html.ToString() });
    }

    private void updateFilterPanel()
    {
        List<Filter> filters = FilterHandler.getInstance().allFilters;

        int count = 0;
        foreach (Filter f in filters) {
            
            TableRow row = (TableRow)Table_Filters.FindControl("row_" + count.ToString());
            row.Visible = true;

            DropDownList d = (DropDownList) row.FindControl("combo_" + count.ToString() + "_a");
            String[] dItems = FilterHandler.getInstance().getAllTitles();
            d.Items.Clear();
            foreach(String s in dItems)
                d.Items.Add(s);
            d.SelectedValue = f.field;

            DropDownList d2 = (DropDownList)row.FindControl("combo_" + count.ToString() + "_b");
            String[] dItems2 = ConvertHandler.getInstance().getModifierChoices(f.field);
            d2.Items.Clear();
            foreach (String s in dItems2)
                d2.Items.Add(s);
            d2.SelectedIndex = 0;

            count++;
        }

        for (int i = count; i < 10; i++) {
            TableRow row = (TableRow)Table_Filters.FindControl("row_" + i.ToString());
            row.Visible = false;
        }

    }

    protected void btn_add_Click(object sender, EventArgs e)
    {
        if (FilterHandler.getInstance().allFilters.Count >= 10)
            return;

        Filter f = new Filter("playerBestOvr", Filter.TYPE_INT);
        f.valueFloat = 93;
        FilterHandler.getInstance().addFilter(f);
        updateFilterPanel();
    }

    protected void btn_get_Click(object sender, EventArgs e)
    {
        BuildTable();
    }

    protected void Remove_Click(object sender, EventArgs e)
    {
        Button btn = (Button)sender;
        FilterHandler.getInstance().allFilters.RemoveAt(Int32.Parse(btn.CommandArgument));
        updateFilterPanel();
    }

    protected void FieldCombo_Change(object sender, EventArgs e)
    {
        DropDownList d = (DropDownList)sender;
        int id = Int32.Parse(d.ID.Split('_')[1]);
        FilterHandler.getInstance().allFilters[id].field = d.SelectedItem.Text; // the selected value is before change
    }

}

And the HTML

<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">


<h2>Player Database</h2>
<div class="row">
    <div class="col-12 col-md-8">
        <p>
            <asp:PlaceHolder ID = "DataTable" runat="server" />
        </p>
    </div>
    <div class="col-6 col-md-4">
        <div  class="col-sm-6"><asp:Button ID="btn_add" runat="server" Text="Add Filter" OnClick="btn_add_Click" class="btn-block btn-primary"/></div>
        <div  class="col-sm-6"><asp:Button ID="btn_get" runat="server" Text="Get" OnClick="btn_get_Click" class="btn-block btn-info"/></div>
        <br>
        <asp:Table id="Table_Filters" runat="server" class="table table-sm table-dark">
                <asp:TableRow ID="row_0" runat="server" visible="false">
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_0_a" class="mdb-select lg-form" OnTextChanged="FieldCombo_Change" AutoPostBack="true"/></asp:TableCell>
                    <asp:TableCell><input id="text_0" type="number" class="textfield" min="0" max="99"/></asp:TableCell>
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_0_b" class="mdb-select lg-form"></asp:DropDownList></asp:TableCell>
                    <asp:TableCell><asp:Button runat="server" CommandArgument="0" OnClick="Remove_Click"  Text="Remove"/></asp:TableCell>
                </asp:TableRow>
                <asp:TableRow ID="row_1" runat="server" visible="false">
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_1_a" class="mdb-select lg-form" OnSelectedIndexChanged="FieldCombo_Change" AutoPostBack="true"/></asp:TableCell>
                    <asp:TableCell><input id="text_1" type="number" class="textfield" min="0" max="99"/></asp:TableCell>
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_1_b" class="mdb-select lg-form"></asp:DropDownList></asp:TableCell>
                    <asp:TableCell><asp:Button runat="server" CommandArgument="1" OnClick="Remove_Click"  Text="Remove"/></asp:TableCell>
                </asp:TableRow>
                <asp:TableRow ID="row_2" runat="server" visible="false">
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_2_a" class="mdb-select lg-form" OnSelectedIndexChanged="FieldCombo_Change" AutoPostBack="true"/></asp:TableCell>
                    <asp:TableCell><input id="text_2" type="number" class="textfield" min="0" max="99"/></asp:TableCell>
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_2_b" class="mdb-select lg-form"></asp:DropDownList></asp:TableCell>
                    <asp:TableCell><asp:Button runat="server" CommandArgument="2" OnClick="Remove_Click"  Text="Remove"/></asp:TableCell>
                </asp:TableRow>
                <asp:TableRow ID="row_3" runat="server" visible="false">
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_3_a" class="mdb-select lg-form" OnSelectedIndexChanged="FieldCombo_Change" AutoPostBack="true"/></asp:TableCell>
                    <asp:TableCell><input id="text_3" type="number" class="textfield" min="0" max="99"/></asp:TableCell>
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_3_b" class="mdb-select lg-form"></asp:DropDownList></asp:TableCell>
                    <asp:TableCell><asp:Button runat="server" CommandArgument="3" OnClick="Remove_Click"  Text="Remove"/></asp:TableCell>
                </asp:TableRow>
                <asp:TableRow ID="row_4" runat="server" visible="false">
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_4_a" class="mdb-select lg-form" OnSelectedIndexChanged="FieldCombo_Change" AutoPostBack="true"/></asp:TableCell>
                    <asp:TableCell><input id="text_4" type="number" class="textfield" min="0" max="99"/></asp:TableCell>
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_4_b" class="mdb-select lg-form"></asp:DropDownList></asp:TableCell>
                    <asp:TableCell><asp:Button runat="server" CommandArgument="4" OnClick="Remove_Click"  Text="Remove"/></asp:TableCell>
                </asp:TableRow>
            <asp:TableRow ID="row_5" runat="server" visible="false">
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_5_a" class="mdb-select lg-form" OnSelectedIndexChanged="FieldCombo_Change" AutoPostBack="true"/></asp:TableCell>
                    <asp:TableCell><input id="text_5" type="number" class="textfield" min="0" max="99"/></asp:TableCell>
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_5_b" class="mdb-select lg-form"></asp:DropDownList></asp:TableCell>
                    <asp:TableCell><asp:Button runat="server" CommandArgument="5" OnClick="Remove_Click"  Text="Remove"/></asp:TableCell>
                </asp:TableRow>
            <asp:TableRow ID="row_6" runat="server" visible="false">
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_6_a" class="mdb-select lg-form" OnSelectedIndexChanged="FieldCombo_Change" AutoPostBack="true"/></asp:TableCell>
                    <asp:TableCell><input id="text_6" type="number" class="textfield" min="0" max="99"/></asp:TableCell>
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_6_b" class="mdb-select lg-form"></asp:DropDownList></asp:TableCell>
                    <asp:TableCell><asp:Button runat="server" CommandArgument="6" OnClick="Remove_Click"  Text="Remove"/></asp:TableCell>
                </asp:TableRow>
            <asp:TableRow ID="row_7" runat="server" visible="false">
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_7_a" class="mdb-select lg-form" OnSelectedIndexChanged="FieldCombo_Change" AutoPostBack="true"/></asp:TableCell>
                    <asp:TableCell><input id="text_7" type="number" class="textfield" min="0" max="99"/></asp:TableCell>
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_7_b" class="mdb-select lg-form"></asp:DropDownList></asp:TableCell>
                    <asp:TableCell><asp:Button runat="server" CommandArgument="7" OnClick="Remove_Click"  Text="Remove"/></asp:TableCell>
                </asp:TableRow>
            <asp:TableRow ID="row_8" runat="server" visible="false">
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_8_a" class="mdb-select lg-form" OnSelectedIndexChanged="FieldCombo_Change" AutoPostBack="true"/></asp:TableCell>
                    <asp:TableCell><input id="text_8" type="number" class="textfield" min="0" max="99"/></asp:TableCell>
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_8_b" class="mdb-select lg-form"></asp:DropDownList></asp:TableCell>
                    <asp:TableCell><asp:Button runat="server" CommandArgument="8" OnClick="Remove_Click"  Text="Remove"/></asp:TableCell>
                </asp:TableRow>
            <asp:TableRow ID="row_9" runat="server" visible="false">
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_9_a" class="mdb-select lg-form" OnSelectedIndexChanged="FieldCombo_Change" AutoPostBack="true"/></asp:TableCell>
                    <asp:TableCell><input id="text_9" type="number" class="textfield" min="0" max="99"/></asp:TableCell>
                    <asp:TableCell><asp:DropDownList runat="server" id="combo_9_b" class="mdb-select lg-form"></asp:DropDownList></asp:TableCell>
                    <asp:TableCell><asp:Button runat="server" CommandArgument="9" OnClick="Remove_Click"  Text="Remove"/></asp:TableCell>
                </asp:TableRow>

        </asp:Table>
    </div>
</div>

</asp:Content>

M. Rogers
  • 367
  • 4
  • 18
  • 1
    Maybe you bind your DropDownList in Page_Load everytime to it's source not only `if(!IsPostBack)` – Tim Schmelter May 11 '21 at 12:58
  • How did you subscribe your DrownDownList to the change event? Could you provide the actual code? – BMI24 May 11 '21 at 13:21
  • I added the HTML lines but those are the only references to the DropDown in my code – M. Rogers May 11 '21 at 16:48
  • Without more information it's impossible to say but if I where to give an educated guess I'd agree with @TimSchmelter. Make sure the data isn't reloading during the `Page_Load` event. It helps to get familiar with the Asp.Net page event life cycle. https://learn.microsoft.com/en-us/previous-versions/aspnet/ms178472(v=vs.100) – asawyer May 11 '21 at 17:07
  • I have attached the full code source – M. Rogers May 11 '21 at 17:46
  • 1
    `ArrayList players` followed immediately by `List filters` ... weird. Anywho it certainly looks like your rebuilding the drop down from the `Page_Load` just as @TimSchmelter and I suspected. Check for `Page.IsPostBack` before blindly resetting controls like that. Also all this server side html table generation is for the birds. You can do all of that with a simple `GridView` component. https://learn.microsoft.com/en-us/dotnet/api/system.web.ui.webcontrols.gridview?view=netframework-4.8 – asawyer May 11 '21 at 17:59

2 Answers2

1

What do you mean "before" the event the value is set? The value is set in the browser, LONG before ANY event on the page fires or can get that value. Once you change the dropdown, and then a post back occurs?

Then the on-load event, and all other page events that fire before the changed event for that combobox will ALL SEE this new value. The page load event always fires each time - for any button click, or change event that fires.

The browser page is sitting client side. The user changes that value - and THEN if their is a post-back, the browser travels up to the server and the code behind runs. All code, all events will see this changed value. It it not like JUST some or one event code runs when the page is posted back up to the server.

You want to always - but near ALWAYS only bind your data sources and controls on the first page load - not each time. Page load will fire for every since event code stub you have FIRST!

So in 99% of cases, without thought, your page load event that loads up things MUST and will ALWAYS have this code stub:

 if IsPostBack = False then
    ' page load and setup code here
     BuildTable();
    updateFilterPanel();

so the drop does NOT change when the code behind triggers or runs - it ALREADY LONG AGO been changed - it was changed while sitting on the users desktop. When any event code behind runs, then the WHOLE web page makes the trip up to the server, and then code behind runs. That includes the page load event EACH time. then the event code stub for the button click or whatever runs.

But EVEN before the page load event, the value(s) are already been changed. You as a developer with code behind NEVER interacts directly with the user, your code behind ONLY interacts with the web browser, and ONLY during that short time after the post-back in which the web page is on the server. once that code is done, then the WHOLE page is sent back to browser, it replots re-displays, and now is ready to interact with the user on the desktop via the browser.

So, any change to any control? it occurs client side and by the user, and LONG BEFORE the code behind will ever run. So a user can change any control. If there is no auto-post back, then they can change as many things the want on that page. if you click a button, or have some auto-post back for the dropddown, then the so called round trip, or post-back starts. So whole page travels up to server side, and code behind starts to run - but any and all controls changed by the user before the post back will have occurred.

In theory, you could pick up any text box, or drop box in ANY event - and even the on-load event you notice that the value of those controls has ALREADY been changed. As a result? You BETTER NOT mess and load up controls each time on the on-load event. The first page load (IsPostBack) is a MUST adopt coding standard. The instant I see loading up code in page load - without a IsPostBack = False then you running code EACH time and every time - and it WILL then re-load and re-setup the controls you had on that page (hence you see the old previous values again). There is not a concept that the control is ONLY changing when the event fires, but in fact as noted, the values in the browser were long time ago changed on the users desktop.

The post-back process sends that WHOLE page up to the server - with all changes already having been made. Your code behind as noted NEVER interacts with the user - it ONLY interacts with the web page - and only during that SHORT TIME and round trip while the web page is up on the server. Once that code is done, the page travels back down to client side, browser displays. On the server side, that page DOES NOT EXIST anymore. (it is tossed out and disposed - that why we call web pages "state-less".

The web page does NOT exist on the server side. It is on the users desktop. So yes, of course any change to any control will occur client side, and LONG BEOFRE the code behind runs. The code behind interacts ONLY during that short period of time when the page is back up on the server. When that code is done, then the WHOLE web page now travels back down to the client side browser, is fully re-loaded and re-plotted, and now you have a fresh new copy of the web page on the users desktop.

So, code behind does not run when you change one control. If you have a auto-post-back = true option for that control? It is not any different then hitting a submit button - the whole page travels up to the server with all current changes and values in all of those controls. So, any changes made client side? When post-back occurs, the values will ALREADY have been changed when the code behind starts to run - and this includes your case.

so any setup code loading of controls etc. that is to occur one time? Wrap that in the on-load event with a IsPostBack check/test.

Albert D. Kallal
  • 42,205
  • 3
  • 34
  • 51
1

When a user submits a form to an Asp.Net Web Forms application the values set by the user are posted to the server application via an HTTP Post request. The request contains both the user's form data as well other bookkeeping information needed by Asp.Net, like the ViewState.

When the server begins processing the request it follows a process known as the Asp.Net Page Lifecycle. This is described in detail on MSDN.

A simplified overview of the process though is that the following steps are taken in order:

Stolen shamelessly from https://stackoverflow.com/q/11235062/426894

So you can see that the Load event occurs before raising post back events. Due to this if a developer forgets to check the Page.IsPostBack flag the load event resets the state of the various form controls. Then when the post back events are raised the default values are all that is read.

Correcting the problem is usually simple - just consider "This is first time my page load has loaded" as a distinctly separate operation or state from all other request types which in turn is, for the most part, as simple as adding:

if(!Page.IsPostBack) { /* All page initialization code goes here only! */ }
asawyer
  • 17,642
  • 8
  • 59
  • 87