6

我确实关注了文章真正了解 ViewState(顺便说一句很棒的文章),并且填充我的下拉列表效果很好。我什至设置了一个几乎一样好的 OnSelectedIndexChange 事件。

我发现的问题是选择第 0 个索引时不会触发 SelectedIndexChanged 事件。然而,它在所有其他时间都这样做。

这是一些代码:

<asp:DropDownList runat="server" ID="DropDownList1" EnableViewState="false" 
AutoPostBack="True" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged" />


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);
    }

我想我可以在 Page_Load 方法中进行某种类型的检查:

  if(ViewState["selectedIndexChangedFlag"] != 1)
      // raise OnSelectedChange event

或者有什么我可以在 OnInit() 方法中设置的东西,我每次都可以重新绑定这些数据?

看,我的自定义 EventHander 引发了一个事件,该事件被该控件所在的父页面捕获,以便父页面可以使用新选择的值执行一些操作。这目前适用于所选索引> 0的所有情况。

我在这个控件中创建了一个包含最近选择的索引的属性,在这种情况下,我的父页面可以在每个 Page_Load 上对这个属性值进行操作......不知道。

接受建议。或者如何强制此 SelectedIndexChanged 事件为第 0 个索引选择触发。

4

2 回答 2

8

问题是您每次都在加载数据,这是重置选定的索引。想象一下这是您的下拉菜单:

zero [selected]
one
two

然后在客户端中更改所选索引:

zero
one [selected]
two

这将__EVENTARGUMENT使用您的新索引 (1) 填充隐藏输入,并__EVENTTARGET使用id下拉列表填充隐藏输入。现在服务器端代码启动并重新加载您的数据:

zero [selected]
one
two

“零”是选定的值,因为这是加载数据时的默认值。然后 ASP.NET在 中查找__EVENTTARGET并找到您的下拉列表并找到新索引 (1)。现在您的下拉列表如下所示:__EVENTARGUMENTRequestid

zero 
one [selected]
two

由于索引已更改,下拉列表会引发其SelectedIndexChanged事件,指示索引已更改。显然这是工作的部分,现在让我们看看为什么选择列表中的第一项不会引发事件。

现在假设我们的下拉菜单仍然处于它刚刚所处的状态(选择“one”并且选择的索引为 1)。当我们在客户端选择列表中的第一项时会发生什么?

__EVENTTARGET并使用下拉列表和新索引 (0)__EVENTARGUMENT填充。id然后服务器将数据加载到下拉列表中,下拉列表现在再次看起来像这样:

zero [selected]
one
two

请注意,由于您在事件触发之前重新加载了数据,因此索引已设置为 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();
    }    
}

如果页面不是回发,这只会将数据加载到下拉列表中。这意味着 ViewState 将为您维护数据以及所选索引,以便在您回发时下拉列表会将新索引与您在客户端中看到的索引进行比较。

于 2009-01-23T20:35:24.880 回答
5

我在此下拉列表中禁用 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);
    }

你是对的。数据在 OnInit 阶段重新加载和重新绑定。然后 ViewState 被恢复(当第 0 个索引被恢复时),当我们最终进入 Events 阶段时,控件没有检测到变化。

不确定这是最优雅的路线,但到目前为止它运行良好。

然后我在 IPostBackDataHandler 的 msdn 文档中找到了这个:

  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;
  }

由于当前值与更改后的值相同,因此不会触发该事件。

于 2009-01-24T00:33:10.033 回答