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

</select>
但是,Postback 之后 attributes就丢失了。
DASM一下 ListItem :
.method assembly hidebysig instance object
SaveViewState() cil managed
{
// Code size 89 (0x59)
.maxstack 4
.locals init (string V_0,
string V_1)
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ldnull
IL_0003: stloc.1
IL_0004: ldarg.0
IL_0005: ldfld bool System.Web.UI.WebControls.ListItem::textisdirty
IL_000a: brfalse.s IL_0013
IL_000c: ldarg.0
IL_000d: call instance string System.Web.UI.WebControls.ListItem::get_Text()
IL_0012: stloc.0
IL_0013: ldarg.0
IL_0014: ldfld bool System.Web.UI.WebControls.ListItem::valueisdirty
IL_0019: brfalse.s IL_0022
IL_001b: ldarg.0
IL_001c: call instance string System.Web.UI.WebControls.ListItem::get_Value()
IL_0021: stloc.1
IL_0022: ldarg.0
IL_0023: ldfld bool System.Web.UI.WebControls.ListItem::enabledisdirty
IL_0028: brfalse.s IL_003d
IL_002a: ldloc.0
IL_002b: ldloc.1
IL_002c: ldarg.0
IL_002d: call instance bool System.Web.UI.WebControls.ListItem::get_Enabled()
IL_0032: box [mscorlib]System.Boolean
IL_0037: newobj instance void System.Web.UI.Triplet::.ctor(object,
object,
object)
IL_003c: ret
IL_003d: ldarg.0
IL_003e: ldfld bool System.Web.UI.WebControls.ListItem::valueisdirty
IL_0043: brfalse.s IL_004d
IL_0045: ldloc.0
IL_0046: ldloc.1
IL_0047: newobj instance void System.Web.UI.Pair::.ctor(object,
object)
IL_004c: ret
IL_004d: ldarg.0
IL_004e: ldfld bool System.Web.UI.WebControls.ListItem::textisdirty
IL_0053: brfalse.s IL_0057
IL_0055: ldloc.0
IL_0056: ret
IL_0057: ldnull
IL_0058: ret
} // 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
get_Attributes() cil managed
{
// Code size 32 (0x20)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld class System.Web.UI.AttributeCollection System.Web.UI.WebControls.ListItem::_attributes
IL_0006: brtrue.s IL_0019
IL_0008: ldarg.0
IL_0009: ldc.i4.1
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_0014: stfld class System.Web.UI.AttributeCollection System.Web.UI.WebControls.ListItem::_attributes
IL_0019: ldarg.0
IL_001a: ldfld class System.Web.UI.AttributeCollection System.Web.UI.WebControls.ListItem::_attributes
IL_001f: ret
} // 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:其实很早都知道这个问题了,竟然直到现在才得以明白,惭愧


























DASM一下 ListItem :





















































SaveViewState确实没有保存Attributes,只是持久化了Text Value Enabled(这个还是按需)三个属性,
其实,ListItem.Attributes 内部都只是简单的如此实现,并没有像常见的有单独一个私有StateBag _attrState 与 AttributeCollection _attrCol出现,只是如果 _atrrCol如果为null,直接传了局部的StateBag 给AttributeCollection构造函数:


















补记:
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:其实很早都知道这个问题了,竟然直到现在才得以明白,惭愧
