这似乎是一个常见的情况,有一个明显的解决方案,但是以某种方式我还没有遇到过。
我有一个DropDownList
,其中有一个绑定到SelectedIndexChanged
事件和AutoPostback="true"
的事件处理程序,它可以按预期工作。
值更改后将执行事件处理程序,但是如果在客户端使用jQuery通过脚本更改了值,则当用户更改值(以及下拉菜单的onchange
事件)时,随后会触发回发触发),则服务器端代码会检测到自服务器上次看到其状态以来该值未更改,因此事件处理程序未在服务器端运行。
似乎可以通过视图状态加载某些内容,但是禁用ViewState
无效。
该页面使用选择的值“ A”呈现下拉菜单。
用户将下拉列表更改为值“ B”。
该值将自动发布到服务器,并执行SelectedIndexChanged
事件处理程序。
运行客户端脚本,使用jQuery.val()
将客户端上的值更改回“ A”。
用户将值改回“ B”。
该值自动发布到服务器,但是由于服务器上次渲染页面时该值为“ 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";
}
最佳答案
在调试.Net Framework Reference Source之后,我得出的结论是DropDownList
实现中存在深层问题,如果不重新实现或继承该类以更改行为,则无法解决该问题。
在DropDownList
类中,有LoadPostData()
接口方法的IPostBackDataHandler
实现。
在LoadPostData()
中,将下拉菜单中当前选择的值的索引与SelectedIndex
属性进行比较,该属性是从ViewState
加载的,或者在下拉菜单中设置了0
时默认为EnableViewState="false"
。OnSelectedIndexChanged()
方法由RaisePostDataChangedEvent()
调用,顾名思义,该方法仅在发布数据与viewstate / default数据相比已更改的情况下才调用。因此,如果当前选择的索引与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);
}