ListItem 的 Attributes 在页面回发(PostBack)之间并不会保持视图状态?
2007-05-13 05:27 晓风残月 阅读(1572) 评论(3) 收藏 举报
偶然之间发现 ListItem 的 Attributes 在页面回发(PostBack)之间并不会保持视图状态,测试如下:
 protected void Page_Load(object sender, EventArgs e)
protected void Page_Load(object sender, EventArgs e)
 {
    {
 if (!Page.IsPostBack) {
        if (!Page.IsPostBack) {
 ListItem item = new ListItem("hi", "0");
            ListItem item = new ListItem("hi", "0");
 item.Attributes["xvalue"] = "x";
            item.Attributes["xvalue"] = "x";
 ListBox1.Items.Add(item);
            ListBox1.Items.Add(item);
 item = new ListItem("hello", "1");
            item = new ListItem("hello", "1");
 item.Attributes["xvalue"] = "y";
            item.Attributes["xvalue"] = "y";
 ListBox1.Items.Add(item);
            ListBox1.Items.Add(item);
 }
        }
 Response.Write("attributes:");
        Response.Write("attributes:");
 Response.Write("<br>");
        Response.Write("<br>");
 foreach (ListItem item in ListBox1.Items) {
        foreach (ListItem item in ListBox1.Items) {
 IEnumerator iterator = item.Attributes.Keys.GetEnumerator();
            IEnumerator iterator = item.Attributes.Keys.GetEnumerator();
 while (iterator.MoveNext()) {
            while (iterator.MoveNext()) {
 string key = iterator.Current.ToString();
                string key = iterator.Current.ToString();
 Response.Write(key + "=" + item.Attributes[key]);
                Response.Write(key + "=" + item.Attributes[key]);
 Response.Write("<br>");
                Response.Write("<br>");
 }
            }
 }
        }
 }
首次加载呈现结果:
    }
首次加载呈现结果:
 <select size="4" name="ListBox1" id="ListBox1">
<select size="4" name="ListBox1" id="ListBox1">
 <option value="0" xvalue="x">hi</option>
    <option value="0" xvalue="x">hi</option>
 <option value="1" xvalue="y">hello</option>
    <option value="1" xvalue="y">hello</option>

 </select>
但是,Postback 之后 attributes就丢失了。
</select>
但是,Postback 之后 attributes就丢失了。
DASM一下 ListItem :
 .method assembly hidebysig instance object
.method assembly hidebysig instance object 
 SaveViewState() cil managed
        SaveViewState() cil managed
 {
{
 // Code size       89 (0x59)
  // Code size       89 (0x59)
 .maxstack  4
  .maxstack  4
 .locals init (string V_0,
  .locals init (string V_0,
 string V_1)
           string V_1)
 IL_0000:  ldnull
  IL_0000:  ldnull
 IL_0001:  stloc.0
  IL_0001:  stloc.0
 IL_0002:  ldnull
  IL_0002:  ldnull
 IL_0003:  stloc.1
  IL_0003:  stloc.1
 IL_0004:  ldarg.0
  IL_0004:  ldarg.0
 IL_0005:  ldfld      bool System.Web.UI.WebControls.ListItem::textisdirty
  IL_0005:  ldfld      bool System.Web.UI.WebControls.ListItem::textisdirty
 IL_000a:  brfalse.s  IL_0013
  IL_000a:  brfalse.s  IL_0013
 IL_000c:  ldarg.0
  IL_000c:  ldarg.0
 IL_000d:  call       instance string System.Web.UI.WebControls.ListItem::get_Text()
  IL_000d:  call       instance string System.Web.UI.WebControls.ListItem::get_Text()
 IL_0012:  stloc.0
  IL_0012:  stloc.0
 IL_0013:  ldarg.0
  IL_0013:  ldarg.0
 IL_0014:  ldfld      bool System.Web.UI.WebControls.ListItem::valueisdirty
  IL_0014:  ldfld      bool System.Web.UI.WebControls.ListItem::valueisdirty
 IL_0019:  brfalse.s  IL_0022
  IL_0019:  brfalse.s  IL_0022
 IL_001b:  ldarg.0
  IL_001b:  ldarg.0
 IL_001c:  call       instance string System.Web.UI.WebControls.ListItem::get_Value()
  IL_001c:  call       instance string System.Web.UI.WebControls.ListItem::get_Value()
 IL_0021:  stloc.1
  IL_0021:  stloc.1
 IL_0022:  ldarg.0
  IL_0022:  ldarg.0
 IL_0023:  ldfld      bool System.Web.UI.WebControls.ListItem::enabledisdirty
  IL_0023:  ldfld      bool System.Web.UI.WebControls.ListItem::enabledisdirty
 IL_0028:  brfalse.s  IL_003d
  IL_0028:  brfalse.s  IL_003d
 IL_002a:  ldloc.0
  IL_002a:  ldloc.0
 IL_002b:  ldloc.1
  IL_002b:  ldloc.1
 IL_002c:  ldarg.0
  IL_002c:  ldarg.0
 IL_002d:  call       instance bool System.Web.UI.WebControls.ListItem::get_Enabled()
  IL_002d:  call       instance bool System.Web.UI.WebControls.ListItem::get_Enabled()
 IL_0032:  box        [mscorlib]System.Boolean
  IL_0032:  box        [mscorlib]System.Boolean
 IL_0037:  newobj     instance void System.Web.UI.Triplet::.ctor(object,
  IL_0037:  newobj     instance void System.Web.UI.Triplet::.ctor(object,
 object,
                                                                  object,
 object)
                                                                  object)
 IL_003c:  ret
  IL_003c:  ret
 IL_003d:  ldarg.0
  IL_003d:  ldarg.0
 IL_003e:  ldfld      bool System.Web.UI.WebControls.ListItem::valueisdirty
  IL_003e:  ldfld      bool System.Web.UI.WebControls.ListItem::valueisdirty
 IL_0043:  brfalse.s  IL_004d
  IL_0043:  brfalse.s  IL_004d
 IL_0045:  ldloc.0
  IL_0045:  ldloc.0
 IL_0046:  ldloc.1
  IL_0046:  ldloc.1
 IL_0047:  newobj     instance void System.Web.UI.Pair::.ctor(object,
  IL_0047:  newobj     instance void System.Web.UI.Pair::.ctor(object,
 object)
                                                               object)
 IL_004c:  ret
  IL_004c:  ret
 IL_004d:  ldarg.0
  IL_004d:  ldarg.0
 IL_004e:  ldfld      bool System.Web.UI.WebControls.ListItem::textisdirty
  IL_004e:  ldfld      bool System.Web.UI.WebControls.ListItem::textisdirty
 IL_0053:  brfalse.s  IL_0057
  IL_0053:  brfalse.s  IL_0057
 IL_0055:  ldloc.0
  IL_0055:  ldloc.0
 IL_0056:  ret
  IL_0056:  ret
 IL_0057:  ldnull
  IL_0057:  ldnull
 IL_0058:  ret
  IL_0058:  ret
 } // end of method ListItem::SaveViewState
} // end of method ListItem::SaveViewState

 
SaveViewState确实没有保存Attributes,只是持久化了Text Value Enabled(这个还是按需)三个属性,
其实,ListItem.Attributes 内部都只是简单的如此实现,并没有像常见的有单独一个私有StateBag _attrState 与 AttributeCollection _attrCol出现,只是如果 _atrrCol如果为null,直接传了局部的StateBag 给AttributeCollection构造函数:
 .method public hidebysig specialname instance class System.Web.UI.AttributeCollection
.method public hidebysig specialname instance class System.Web.UI.AttributeCollection 
 get_Attributes() cil managed
        get_Attributes() cil managed
 {
{
 // Code size       32 (0x20)
  // Code size       32 (0x20)
 .maxstack  8
  .maxstack  8
 IL_0000:  ldarg.0
  IL_0000:  ldarg.0
 IL_0001:  ldfld      class System.Web.UI.AttributeCollection System.Web.UI.WebControls.ListItem::_attributes
  IL_0001:  ldfld      class System.Web.UI.AttributeCollection System.Web.UI.WebControls.ListItem::_attributes
 IL_0006:  brtrue.s   IL_0019
  IL_0006:  brtrue.s   IL_0019
 IL_0008:  ldarg.0
  IL_0008:  ldarg.0
 IL_0009:  ldc.i4.1
  IL_0009:  ldc.i4.1
 IL_000a:  newobj     instance void System.Web.UI.StateBag::.ctor(bool)
  IL_000a:  newobj     instance void System.Web.UI.StateBag::.ctor(bool)
 IL_000f:  newobj     instance void System.Web.UI.AttributeCollection::.ctor(class System.Web.UI.StateBag)
  IL_000f:  newobj     instance void System.Web.UI.AttributeCollection::.ctor(class System.Web.UI.StateBag)
 IL_0014:  stfld      class System.Web.UI.AttributeCollection System.Web.UI.WebControls.ListItem::_attributes
  IL_0014:  stfld      class System.Web.UI.AttributeCollection System.Web.UI.WebControls.ListItem::_attributes
 IL_0019:  ldarg.0
  IL_0019:  ldarg.0
 IL_001a:  ldfld      class System.Web.UI.AttributeCollection System.Web.UI.WebControls.ListItem::_attributes
  IL_001a:  ldfld      class System.Web.UI.AttributeCollection System.Web.UI.WebControls.ListItem::_attributes
 IL_001f:  ret
  IL_001f:  ret
 } // end of method ListItem::get_Attributes
} // end of method ListItem::get_Attributes
 
补记:
1。其实在 asp.net 1.x 设置ListItem.Attribtues,ListItem 并不会呈现这些 Attributes,已经被视为bug,虽然 2.0 做了改进,依然有问题。参见: ListControl Items and Attributes,
2。之前,为了给Checkbox设置一个客户端可用的 value ,偶尝试自定义了一个 带Value属性的扩展CheckBox控件,因为对于 value 这个Attribute,CheckBox内部好像对 ListItem 实现了强制性过滤。
3。早上baidu了一下,发现很多网友有类似的疑问,并提供了多种解决方案,
如何使CheckBoxList的Attributes属性生效(修改微软的一个bug).
非常有趣的是这个方案是通过重载Render方法,并将HtmlTextWriter输出文本,然后搜索匹配插入需要的 attribute
4。之前转载的一篇文章解决了这个问题:
[转]ListControl Items, Attributes, and ViewState
值得注意的是,这里 Scott Mitchell 采取的策略是分别扩展 DropDownList、CheckBoxlist等,而不是直接扩展 ListItem,减轻了工作量,详细见文章。
PS:其实很早都知道这个问题了,竟然直到现在才得以明白,惭愧 
 
 protected void Page_Load(object sender, EventArgs e)
protected void Page_Load(object sender, EventArgs e) {
    { if (!Page.IsPostBack) {
        if (!Page.IsPostBack) { ListItem item = new ListItem("hi", "0");
            ListItem item = new ListItem("hi", "0"); item.Attributes["xvalue"] = "x";
            item.Attributes["xvalue"] = "x"; ListBox1.Items.Add(item);
            ListBox1.Items.Add(item); item = new ListItem("hello", "1");
            item = new ListItem("hello", "1"); item.Attributes["xvalue"] = "y";
            item.Attributes["xvalue"] = "y"; ListBox1.Items.Add(item);
            ListBox1.Items.Add(item); }
        } Response.Write("attributes:");
        Response.Write("attributes:"); Response.Write("<br>");
        Response.Write("<br>"); foreach (ListItem item in ListBox1.Items) {
        foreach (ListItem item in ListBox1.Items) { IEnumerator iterator = item.Attributes.Keys.GetEnumerator();
            IEnumerator iterator = item.Attributes.Keys.GetEnumerator(); while (iterator.MoveNext()) {
            while (iterator.MoveNext()) { string key = iterator.Current.ToString();
                string key = iterator.Current.ToString(); Response.Write(key + "=" + item.Attributes[key]);
                Response.Write(key + "=" + item.Attributes[key]); Response.Write("<br>");
                Response.Write("<br>"); }
            } }
        } }
    } <select size="4" name="ListBox1" id="ListBox1">
<select size="4" name="ListBox1" id="ListBox1"> <option value="0" xvalue="x">hi</option>
    <option value="0" xvalue="x">hi</option> <option value="1" xvalue="y">hello</option>
    <option value="1" xvalue="y">hello</option>
 </select>
</select>DASM一下 ListItem :
 .method assembly hidebysig instance object
.method assembly hidebysig instance object  SaveViewState() cil managed
        SaveViewState() cil managed {
{ // Code size       89 (0x59)
  // Code size       89 (0x59) .maxstack  4
  .maxstack  4 .locals init (string V_0,
  .locals init (string V_0, string V_1)
           string V_1) IL_0000:  ldnull
  IL_0000:  ldnull IL_0001:  stloc.0
  IL_0001:  stloc.0 IL_0002:  ldnull
  IL_0002:  ldnull IL_0003:  stloc.1
  IL_0003:  stloc.1 IL_0004:  ldarg.0
  IL_0004:  ldarg.0 IL_0005:  ldfld      bool System.Web.UI.WebControls.ListItem::textisdirty
  IL_0005:  ldfld      bool System.Web.UI.WebControls.ListItem::textisdirty IL_000a:  brfalse.s  IL_0013
  IL_000a:  brfalse.s  IL_0013 IL_000c:  ldarg.0
  IL_000c:  ldarg.0 IL_000d:  call       instance string System.Web.UI.WebControls.ListItem::get_Text()
  IL_000d:  call       instance string System.Web.UI.WebControls.ListItem::get_Text() IL_0012:  stloc.0
  IL_0012:  stloc.0 IL_0013:  ldarg.0
  IL_0013:  ldarg.0 IL_0014:  ldfld      bool System.Web.UI.WebControls.ListItem::valueisdirty
  IL_0014:  ldfld      bool System.Web.UI.WebControls.ListItem::valueisdirty IL_0019:  brfalse.s  IL_0022
  IL_0019:  brfalse.s  IL_0022 IL_001b:  ldarg.0
  IL_001b:  ldarg.0 IL_001c:  call       instance string System.Web.UI.WebControls.ListItem::get_Value()
  IL_001c:  call       instance string System.Web.UI.WebControls.ListItem::get_Value() IL_0021:  stloc.1
  IL_0021:  stloc.1 IL_0022:  ldarg.0
  IL_0022:  ldarg.0 IL_0023:  ldfld      bool System.Web.UI.WebControls.ListItem::enabledisdirty
  IL_0023:  ldfld      bool System.Web.UI.WebControls.ListItem::enabledisdirty IL_0028:  brfalse.s  IL_003d
  IL_0028:  brfalse.s  IL_003d IL_002a:  ldloc.0
  IL_002a:  ldloc.0 IL_002b:  ldloc.1
  IL_002b:  ldloc.1 IL_002c:  ldarg.0
  IL_002c:  ldarg.0 IL_002d:  call       instance bool System.Web.UI.WebControls.ListItem::get_Enabled()
  IL_002d:  call       instance bool System.Web.UI.WebControls.ListItem::get_Enabled() IL_0032:  box        [mscorlib]System.Boolean
  IL_0032:  box        [mscorlib]System.Boolean IL_0037:  newobj     instance void System.Web.UI.Triplet::.ctor(object,
  IL_0037:  newobj     instance void System.Web.UI.Triplet::.ctor(object, object,
                                                                  object, object)
                                                                  object) IL_003c:  ret
  IL_003c:  ret IL_003d:  ldarg.0
  IL_003d:  ldarg.0 IL_003e:  ldfld      bool System.Web.UI.WebControls.ListItem::valueisdirty
  IL_003e:  ldfld      bool System.Web.UI.WebControls.ListItem::valueisdirty IL_0043:  brfalse.s  IL_004d
  IL_0043:  brfalse.s  IL_004d IL_0045:  ldloc.0
  IL_0045:  ldloc.0 IL_0046:  ldloc.1
  IL_0046:  ldloc.1 IL_0047:  newobj     instance void System.Web.UI.Pair::.ctor(object,
  IL_0047:  newobj     instance void System.Web.UI.Pair::.ctor(object, object)
                                                               object) IL_004c:  ret
  IL_004c:  ret IL_004d:  ldarg.0
  IL_004d:  ldarg.0 IL_004e:  ldfld      bool System.Web.UI.WebControls.ListItem::textisdirty
  IL_004e:  ldfld      bool System.Web.UI.WebControls.ListItem::textisdirty IL_0053:  brfalse.s  IL_0057
  IL_0053:  brfalse.s  IL_0057 IL_0055:  ldloc.0
  IL_0055:  ldloc.0 IL_0056:  ret
  IL_0056:  ret IL_0057:  ldnull
  IL_0057:  ldnull IL_0058:  ret
  IL_0058:  ret } // end of method ListItem::SaveViewState
} // end of method ListItem::SaveViewState

SaveViewState确实没有保存Attributes,只是持久化了Text Value Enabled(这个还是按需)三个属性,
其实,ListItem.Attributes 内部都只是简单的如此实现,并没有像常见的有单独一个私有StateBag _attrState 与 AttributeCollection _attrCol出现,只是如果 _atrrCol如果为null,直接传了局部的StateBag 给AttributeCollection构造函数:
 .method public hidebysig specialname instance class System.Web.UI.AttributeCollection
.method public hidebysig specialname instance class System.Web.UI.AttributeCollection  get_Attributes() cil managed
        get_Attributes() cil managed {
{ // Code size       32 (0x20)
  // Code size       32 (0x20) .maxstack  8
  .maxstack  8 IL_0000:  ldarg.0
  IL_0000:  ldarg.0 IL_0001:  ldfld      class System.Web.UI.AttributeCollection System.Web.UI.WebControls.ListItem::_attributes
  IL_0001:  ldfld      class System.Web.UI.AttributeCollection System.Web.UI.WebControls.ListItem::_attributes IL_0006:  brtrue.s   IL_0019
  IL_0006:  brtrue.s   IL_0019 IL_0008:  ldarg.0
  IL_0008:  ldarg.0 IL_0009:  ldc.i4.1
  IL_0009:  ldc.i4.1 IL_000a:  newobj     instance void System.Web.UI.StateBag::.ctor(bool)
  IL_000a:  newobj     instance void System.Web.UI.StateBag::.ctor(bool) IL_000f:  newobj     instance void System.Web.UI.AttributeCollection::.ctor(class System.Web.UI.StateBag)
  IL_000f:  newobj     instance void System.Web.UI.AttributeCollection::.ctor(class System.Web.UI.StateBag) IL_0014:  stfld      class System.Web.UI.AttributeCollection System.Web.UI.WebControls.ListItem::_attributes
  IL_0014:  stfld      class System.Web.UI.AttributeCollection System.Web.UI.WebControls.ListItem::_attributes IL_0019:  ldarg.0
  IL_0019:  ldarg.0 IL_001a:  ldfld      class System.Web.UI.AttributeCollection System.Web.UI.WebControls.ListItem::_attributes
  IL_001a:  ldfld      class System.Web.UI.AttributeCollection System.Web.UI.WebControls.ListItem::_attributes IL_001f:  ret
  IL_001f:  ret } // end of method ListItem::get_Attributes
} // end of method ListItem::get_Attributes
补记:
1。其实在 asp.net 1.x 设置ListItem.Attribtues,ListItem 并不会呈现这些 Attributes,已经被视为bug,虽然 2.0 做了改进,依然有问题。参见: ListControl Items and Attributes,
2。之前,为了给Checkbox设置一个客户端可用的 value ,偶尝试自定义了一个 带Value属性的扩展CheckBox控件,因为对于 value 这个Attribute,CheckBox内部好像对 ListItem 实现了强制性过滤。
3。早上baidu了一下,发现很多网友有类似的疑问,并提供了多种解决方案,
如何使CheckBoxList的Attributes属性生效(修改微软的一个bug).
非常有趣的是这个方案是通过重载Render方法,并将HtmlTextWriter输出文本,然后搜索匹配插入需要的 attribute
4。之前转载的一篇文章解决了这个问题:
[转]ListControl Items, Attributes, and ViewState
值得注意的是,这里 Scott Mitchell 采取的策略是分别扩展 DropDownList、CheckBoxlist等,而不是直接扩展 ListItem,减轻了工作量,详细见文章。
PS:其实很早都知道这个问题了,竟然直到现在才得以明白,惭愧
 
 
 
                    
                     
                    
                 
                    
                 
    
 
         
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号