2

这似乎是一个有明显解决方案的常见场景,但不知何故我还没有遇到过。

我有一个DropDownList与事件绑定的事件处理程序SelectedIndexChangedAutoPostback="true"并且按预期工作。

事件处理程序在值发生更改时执行,但如果在客户端使用 jQuery 通过脚本更改值,并且随后在用户更改值时触发回发(并且下拉onchange事件触发),然后服务器端代码检测到自服务器上次看到其状态以来该值没有更改,因此事件处理程序不在服务器端运行。

似乎可以通过视图状态加载某些内容,但禁用ViewState无效。

  1. 该页面呈现下拉菜单并选择了值“A”。
  2. 用户将下拉列表更改为值“B”。
  3. 该值会自动发布到服务器,并SelectedIndexChanged执行事件处理程序。
  4. 运行客户端脚本以使用 将客户端上的值更改回“A” jQuery.val()
  5. 用户将值改回“B”。
  6. 该值会自动发布到服务器,但由于在服务器上次呈现页面时该值为“B”,因此SelectedIndexChanged不会执行事件处理程序。

客户端

<asp:DropDownList ID="dlst" runat="server" AutoPostBack="true" OnSelectedIndexChanged="dlst_SelectedIndexChanged">
    <asp:ListItem Text="A" Value="A" />
    <asp:ListItem Text="B" Value="B" />
</asp:DropDownList>

<asp:Button ID="btnChange" runat="server" Text="Change" OnClientClick="return changeDDL(this,event)" />
<script type="text/javascript">
    function changeDDL(sender, e) {
        var dlst = $("#<%= dlst.ClientID %>");
        dlst.val(dlst.val() === "A" ? "B" : "A");
        return false;
    }
</script>

服务器端

protected void dlst_SelectedIndexChanged(object sender, EventArgs e)
{
    btnChange.Text = dlst.SelectedValue == "A" ? "Change B" : "Change A";
}
4

1 回答 1

2

调试.Net Framework Reference Source后,我得出结论,问题在DropDownList实现中很深,如果不重新实现或继承类来改变行为,就无法解决。

DropDownList类中,有一个接口方法的LoadPostData()实现。IPostBackDataHandler

在内部LoadPostData(),当前在下拉列表中选择的值的索引将与在下拉列表中设置的加载或默认设置的属性SelectedIndex进行ViewState比较。0EnableViewState="false"

OnSelectedIndexChanged()方法由 调用,RaisePostDataChangedEvent()顾名思义,只有在发布数据与视图状态/默认数据相比发生更改时才会调用该方法。因此,如果当前选择的索引与视图状态/默认索引匹配,SelectedIndexChanged则不会触发该事件。

就我而言,有两件事可能导致问题:

  1. ViewState启用后,当前索引值与从中加载的值匹配,SelectedIndex因此ViewState不会SelectedIndexChanged触发。
  2. ViewState禁用时,该值SelectedIndex默认为0,因此当当前索引值为 时0SelectedIndexChanged不会触发。

DropDownList.LoadPostData()

protected virtual bool LoadPostData(String postDataKey, NameValueCollection postCollection) { 
    //{snip...}
    int n = Items.FindByValueInternal(selectedItems[0], false);

    if (SelectedIndex != n) {
        SetPostDataSelection(n); // Calls ListControl.SetPostDataSelection() and sets Items[selectedIndex].Selected = true;
        return true;
    } 

    return false; 
}

稍后,当类通过其发布数据已更改的控件时,如果检测到更改,则调用Page下拉菜单的方法。OnSelectedIndexChanged由于在这种情况下下拉列表的发布数据没有更改,因此不会引发事件。

DropDownList.RaisePostDataChangedEvent()

protected virtual void RaisePostDataChangedEvent() { 
    //{snip...}
    OnSelectedIndexChanged(EventArgs.Empty); 
} 
于 2012-10-27T20:29:07.717 回答