简体   繁体   English

为什么 ASP.NET DropDownList 更改侦听器“SelectedItem”是旧项目?

[英]Why ASP.NET DropDownList Change listener "SelectedItem" is old item?

I'm surprised at how difficult this question has been for me.我很惊讶这个问题对我来说有多么困难。 I have a OnSelectedIndexChanged listener for a asp:DropDownList that fires correctly.我有一个正确触发的 asp:DropDownList 的 OnSelectedIndexChanged 侦听器。 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.但是,在我的侦听器方法中,“SelectedItem.Text”在触发事件之前返回 DropDownList 的值。 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和 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> </asp:内容>

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.然后,加载事件以及在该 combobox 的更改事件之前触发的所有其他页面事件都将看到这个新值。 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:因此,在 99% 的情况下,您的页面加载事件会在不经意间加载内容,并且必须并且总是有这个代码存根:

 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.因此,当触发或运行背后的代码时,drop 不会改变——它已经很久以前改变了——它在用户桌面上被改变了。 When any event code behind runs, then the WHOLE web page makes the trip up to the server, and then code behind runs.当后面的任何事件代码运行时,整个 web 页面会到达服务器,然后代码后面运行。 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.作为开发人员,您永远不会直接与用户交互,您的代码仅与 web 浏览器交互,并且仅在 web 页面在服务器上的回发后的短时间内进行交互。 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.第一个页面加载(IsPostBack)是必须采用的编码标准。 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).我看到在页面加载中加载代码的那一刻 - 没有 IsPostBack = False 然后你每次都运行代码 - 然后它将重新加载并重新设置你在该页面上拥有的控件(因此你会看到旧的之前的值)。 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.如前所述,您的代码永远不会与用户交互 - 它仅与 web 页面交互 - 并且仅在 web 页面在服务器上启动时的短时间和往返期间。 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". (它被扔掉了——这就是为什么我们称 web 页面“无状态”。

The web page does NOT exist on the server side.服务器端不存在 web 页面。 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.完成该代码后,整个 web 页面现在返回客户端浏览器,完全重新加载并重新绘制,现在您在用户桌面上拥有 web 页面的全新副本。

So, code behind does not run when you change one control.因此,当您更改一个控件时,后面的代码不会运行。 If you have a auto-post-back = true option for that control?如果您有该控件的 auto-post-back = true 选项? 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.使用 IsPostBack 检查/测试将其包装在 on-load 事件中。

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.当用户向 Asp.Net Web Forms 应用程序提交表单时,用户设置的值将通过 HTTP 发布请求发布到服务器应用程序。 The request contains both the user's form data as well other bookkeeping information needed by Asp.Net, like the ViewState .该请求既包含用户的表单数据,也包含 Asp.Net 所需的其他簿记信息,例如ViewState

When the server begins processing the request it follows a process known as the Asp.Net Page Lifecycle.当服务器开始处理请求时,它遵循称为 Asp.Net 页面生命周期的过程。 This is described in detail on MSDN . 这在 MSDN 上有详细描述

A simplified overview of the process though is that the following steps are taken in order:该过程的简化概述是按顺序执行以下步骤:

从 https://stackoverflow.com/q/11235062/426894 无耻窃取

So you can see that the Load event occurs before raising post back events.因此,您可以看到 Load 事件发生在引发回发事件之前。 Due to this if a developer forgets to check the Page.IsPostBack flag the load event resets the state of the various form controls.因此,如果开发人员忘记检查Page.IsPostBack标志,则加载事件会重置各种表单控件的 state。 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:纠正问题通常很简单 - 只需将“这是我的页面加载第一次加载”视为一个明显独立的操作,或者将 state 与所有其他请求类型考虑,而在大多数情况下,就像添加一样简单:

if(!Page.IsPostBack) { /* All page initialization code goes here only! */ }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM