Dav*_*nov 6 asp.net viewstate user-controls selectedindexchanged drop-down-menu
我确实按照文章TRULLY了解ViewState(很棒的文章btw)并填充我的下拉列表工作得很好.我甚至设置了一个OnSelectedIndexChange事件,它几乎同样激发.
我发现的问题是在选择第0个索引时不会触发SelectedIndexChanged事件.然而,它会做所有其他时间.
这是一些代码:
<asp:DropDownList runat="server" ID="DropDownList1" EnableViewState="false"
AutoPostBack="True" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged" />
Run Code Online (Sandbox Code Playgroud)
protected override void OnInit(EventArgs e)
{
this.DropDownList1.DataTextField = "Text";
this.DropDownList1.DataValueField = "Value";
this.DropDownList1.DataSource = fillQueueDropDown();
this.DropDownList1.DataBind();
base.OnInit(e);
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
OnSelectedQueueChanged(e);
}
public void OnSelectedQueueChanged(EventArgs e)
{
// Do stuff.
}
public event EventHandler queueNamesChangedEvent;
public void OnSelectedQueueChanged(EventArgs e)
{
if (queueNamesChangedEvent != null)
queueNamesChangedEvent(this, e);
}
Run Code Online (Sandbox Code Playgroud)
我想我可以在Page_Load方法中进行某种类型的检查:
if(ViewState["selectedIndexChangedFlag"] != 1)
// raise OnSelectedChange event
Run Code Online (Sandbox Code Playgroud)
或者我可以在OnInit()方法中设置一些东西,我每次都可以重新绑定这些数据吗?
请参阅,我的自定义EventHander引发一个事件,该事件由此控件所在的父页面捕获,以便父级可以使用新选择的值执行某些操作.这目前适用于所选索引> 0的所有情况.
我在此控件中创建了一个属性,其中包含最近选择的索引,在这种情况下,我的父页面可以对每个Page_Load ... dunno上的此属性值执行操作.
接受建议.或者如何强制此SelectedIndexChanged事件触发第0个索引选择.
问题是您每次都在加载数据,这会重置所选索引.想象一下这是你的下拉菜单:
zero [selected]
one
two
Run Code Online (Sandbox Code Playgroud)
然后在客户端中更改所选索引:
zero
one [selected]
two
Run Code Online (Sandbox Code Playgroud)
这将__EVENTARGUMENT使用您的新索引(1)填充隐藏的输入,并__EVENTTARGET使用id您的下拉列表填充隐藏的输入.现在服务器端代码启动并重新加载您的数据:
zero [selected]
one
two
Run Code Online (Sandbox Code Playgroud)
"零"是选定的值,因为这是加载数据时的默认值.然后ASP.NET查找__EVENTTARGET并__EVENTARGUMENT在其中Request找到您的下拉列表id并找到新索引(1).现在您的下拉列表如下所示:
zero
one [selected]
two
Run Code Online (Sandbox Code Playgroud)
由于索引已更改,因此下拉列表会引发其SelectedIndexChanged事件,指示索引已更改.显然这是正在运行的部分,现在让我们看看为什么选择列表中的第一项不会引发事件.
现在让我们说我们仍然在其所处的状态下拉(选择"一个"并且选择的索引为1).当我们选择客户端列表中的第一个项目时会发生什么?
__EVENTTARGET并__EVENTARGUMENT使用id下拉列表和新索引(0)填充.然后服务器将数据加载到下拉列表中,下拉列表现在再次显示如下:
zero [selected]
one
two
Run Code Online (Sandbox Code Playgroud)
请注意,由于您在事件触发之前重新加载了数据,因此索引已设置为0,因为这是默认值.现在,当您的事件触发并且下拉列表的选定索引设置为0时,下拉列表不会将此视为更改,因为所选索引(据其所知)尚未更改.
以下是解决问题的方法:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (!Page.IsPostBack)
{
this.DropDownList1.DataTextField = "Text";
this.DropDownList1.DataValueField = "Value";
this.DropDownList1.DataSource = fillQueueDropDown();
this.DropDownList1.DataBind();
}
}
Run Code Online (Sandbox Code Playgroud)
这样做只会在页面不是回发时将数据加载到下拉列表中.这意味着ViewState将为您维护数据以及所选索引,以便在您回发下拉列表时将新索引与您在客户端中看到的索引进行比较.
我在此下拉列表中禁用ViewState的目的是最小化页面的ViewState大小.
我只做if(!Page.IsPostBack){... DataBind()...}的问题是,当你第一次选择一个项目并且页面重新加载时,我的下拉列表变为空.
我最终做的是在这个控件上创建另一个属性LastIndex.触发OnSelectedIndexChanged事件时,我更新LastIndex值.在Page_Load中,我比较Current和Last索引值,如果它们不同,则触发Index changed事件.
public int SelectedValue{
get { return this.DropDownList1.SelectedItem.Value; }
}
public int LastIndex{
get { return this.ViewState["lastIndex"] == null ? -1 : (int)this.ViewState["lastIndex"]; }
set { this.ViewState["lastIndex"] = value; }
}
protected override void OnInit(EventArgs e){
base.OnInit(e);
this.DropDownList1.DataTextField = "Text";
this.DropDownList1.DataValueField = "Value";
this.DropDownList1.DataSource = fillQueueDropDown();
this.DropDownList1.DataBind();
}
protected void Page_Load(object sender, EventArgs e){
if (this.LastIndex != this.SelectedValue)
this.OnSelectedQueueChanged(new EventArgs());
}
private ListItemCollection fillQueueDropDown(){...}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e){
OnSelectedQueueChanged(e);
this.LastIndex = this.SelectedValue;
}
public event EventHandler queueNamesChangedEvent;
public void OnSelectedQueueChanged(EventArgs e){
if (queueNamesChangedEvent != null)
queueNamesChangedEvent(this, e);
}
Run Code Online (Sandbox Code Playgroud)
你是对的.数据在OnInit阶段重新加载并重新绑定.然后恢复ViewState(当第0个索引恢复时),当我们最终进入事件阶段时,控件不会检测到更改.
不确定这是最优雅的路线,但它到目前为止工作得很好.
然后我在msdn docs for IPostBackDataHandler中找到了这个:
public virtual bool LoadPostData(string postDataKey,
NameValueCollection postCollection) {
String presentValue = Text;
String postedValue = postCollection[postDataKey];
if (presentValue == null || !presentValue.Equals(postedValue)) {
Text = postedValue;
return true;
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
由于当前值与更改为的值相同,因此不会触发事件.