这似乎是一个常见的场景,有一个明显的解决方案,但不知怎的,我没有遇到过它。
我有一个DropDownList
,其中一个事件处理程序绑定到SelectedIndexChanged
事件和AutoPostback="true"
,它按预期工作。
当值已更改时执行事件处理程序,但是如果在客户端使用jQuery通过脚本更改了值,则在用户更改值时会触发回发(以及下拉列表{ {1}}事件触发),然后服务器端代码检测到自服务器上次查看其状态后该值未发生更改,因此事件处理程序未在服务器端运行。
似乎会通过视图状态加载,但禁用onchange
无效。
ViewState
事件处理程序。SelectedIndexChanged
将客户端上的值更改回“A”。jQuery.val()
事件处理程序。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>
答案 0 :(得分:2)
在调试.Net Framework Reference Source之后,我得出结论问题在DropDownList
实现中很深,如果没有重新实现或继承类来改变行为,就无法解决问题。
在DropDownList
类中,LoadPostData()
接口方法有IPostBackDataHandler
个实现。
在LoadPostData()
内,将下拉列表中当前所选值的索引与从SelectedIndex
加载或默认为ViewState
的{{1}}属性进行比较在下拉列表中设置0
时。
EnableViewState="false"
方法调用OnSelectedIndexChanged()
方法,正如名称所示,只有在发布数据与viewstate / default数据相比发生变化时才会调用RaisePostDataChangedEvent()
方法。因此,如果当前选定的索引与viewstate / default索引匹配,则SelectedIndexChanged
事件不会触发。
就我而言,有两件事可能导致问题:
ViewState
后,当前索引值与SelectedIndex
加载的ViewState
值相匹配,因此SelectedIndexChanged
不会触发。ViewState
后,SelectedIndex
值默认为0
,因此当前索引值为0
时,SelectedIndexChanged
不会触发。 <强> 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);
}