DropDownList中的ListItems属性在回发时会丢失吗?

Dav*_*son 69 asp.net postback behavior listitem drop-down-menu

一位同事告诉我这个:

他有一个DropDownList和一个网页上的按钮.这是背后的代码:

protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            ListItem item = new ListItem("1");
            item.Attributes.Add("title", "A");

            ListItem item2 = new ListItem("2");
            item2.Attributes.Add("title", "B");

            DropDownList1.Items.AddRange(new[] {item, item2});
            string s = DropDownList1.Items[0].Attributes["title"];
        }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        DropDownList1.Visible = !DropDownList1.Visible;
    }
Run Code Online (Sandbox Code Playgroud)

在页面加载时,项目的工具提示正在显示,但在第一次回发时,属性将丢失.为什么会这样,有没有解决方法?

Lar*_*mie 70

我有同样的问题,并希望贡献资源,其中作者创建了一个继承的ListItem使用者以将属性持久化到ViewState.希望它会浪费我浪费的时间,直到我偶然发现它.

protected override object SaveViewState()
{
    // create object array for Item count + 1
    object[] allStates = new object[this.Items.Count + 1];

    // the +1 is to hold the base info
    object baseState = base.SaveViewState();
    allStates[0] = baseState;

    Int32 i = 1;
    // now loop through and save each Style attribute for the List
    foreach (ListItem li in this.Items)
    {
        Int32 j = 0;
        string[][] attributes = new string[li.Attributes.Count][];
        foreach (string attribute in li.Attributes.Keys)
        {
            attributes[j++] = new string[] {attribute, li.Attributes[attribute]};
        }
        allStates[i++] = attributes;
    }
    return allStates;
}

protected override void LoadViewState(object savedState)
{
    if (savedState != null)
    {
        object[] myState = (object[])savedState;

        // restore base first
        if (myState[0] != null)
            base.LoadViewState(myState[0]);

        Int32 i = 1;
        foreach (ListItem li in this.Items)
        {
            // loop through and restore each style attribute
            foreach (string[] attribute in (string[][])myState[i++])
            {
                li.Attributes[attribute[0]] = attribute[1];
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 您必须从DropDownList继承一个类,然后使用它,就像gleapman在下面解释的那样;) (2认同)
  • 解决方案涉及创建一个我不喜欢的新控件.有一种方法可以在没有任何子类化的情况下完成此操作. (2认同)

小智 36

谢谢,拉勒米.正是我在寻找的东西.它完美地保持了属性.

要展开,下面是我使用Laramie的代码创建的类文件,用于在VS2008中创建下拉列表.在App_Code文件夹中创建类.创建类后,在aspx页面上使用此行进行注册:

<%@ Register TagPrefix="aspNewControls" Namespace="NewControls"%>
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用此控件在您的webform上

<aspNewControls:NewDropDownList ID="ddlWhatever" runat="server">
                                                </aspNewControls:NewDropDownList>
Run Code Online (Sandbox Code Playgroud)

好的,这是班级......

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Security.Permissions;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace NewControls
{
  [DefaultProperty("Text")]
  [ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1>")]
  public class NewDropDownList : DropDownList
  {
    [Bindable(true)]
    [Category("Appearance")]
    [DefaultValue("")]
    [Localizable(true)]

    protected override object SaveViewState()
    {
        // create object array for Item count + 1
        object[] allStates = new object[this.Items.Count + 1];

        // the +1 is to hold the base info
        object baseState = base.SaveViewState();
        allStates[0] = baseState;

        Int32 i = 1;
        // now loop through and save each Style attribute for the List
        foreach (ListItem li in this.Items)
        {
            Int32 j = 0;
            string[][] attributes = new string[li.Attributes.Count][];
            foreach (string attribute in li.Attributes.Keys)
            {
                attributes[j++] = new string[] { attribute, li.Attributes[attribute] };
            }
            allStates[i++] = attributes;
        }
        return allStates;
    }

    protected override void LoadViewState(object savedState)
    {
        if (savedState != null)
        {
            object[] myState = (object[])savedState;

            // restore base first
            if (myState[0] != null)
                base.LoadViewState(myState[0]);

            Int32 i = 1;
            foreach (ListItem li in this.Items)
            {
                // loop through and restore each style attribute
                foreach (string[] attribute in (string[][])myState[i++])
                {
                    li.Attributes[attribute[0]] = attribute[1];
                }
            }
        }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我试过你的解决方案,但如果我使用你的继承控制,它在后面的代码中以某种方式无法访问。我的意思是,如果我尝试 `ddlWhatever.Items`,它会从 `ddlWhatever` 中抛出 null 异常知道为什么吗? (2认同)

小智 13

简单的解决方案是pre-render在下拉列表中添加工具提示属性.对状态的任何更改都应该在pre-render事件中完成.

示例代码:

protected void drpBrand_PreRender(object sender, EventArgs e)
        {
            foreach (ListItem _listItem in drpBrand.Items)
            {
                _listItem.Attributes.Add("title", _listItem.Text);
            }
            drpBrand.Attributes.Add("onmouseover", "this.title=this.options[this.selectedIndex].title");
        }
Run Code Online (Sandbox Code Playgroud)


And*_*are 8

如果您只想在第一次加载页面时加载listitems,那么您需要启用ViewState,以便控件可以序列化其状态并在页面回发时重新加载.

有几个地方可以启用ViewState - 检查<pages/>web.config中的节点以及<%@ page %>aspx文件本身顶部的指令中的EnableViewState属性.此设置需要trueViewState才能工作.

如果您不想使用ViewState,只需删除if (!IsPostBack) { ... }添加的代码周围的内容,ListItems并在每次回发时重新创建项目.

编辑:我道歉 - 我误解了你的问题.你是正确的,因为它们没有在ViewState中序列化,所以属性不会在回发中存活.您必须在每个回发上重新添加这些属性.


小智 6

一个简单的解决方案 - 在请求回发的点击事件上调用您的下拉加载功能.