A coworker showed me this:
He has a DropDownList and a button on a web page. Here's the code behind:
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;
}
On the page load, the items' tooltips are showing, but on the first postback, the attributes are lost. Why is this the case, and are there any workarounds?
Here's the VB.Net code of the solution proposed by Laramie and refined by gleapman.
Update: The code I posted below is actually for the ListBox control. Just change the inheritance to DropDownList and rename the class.
I managed to achieve that using Session Variables, in my case my list is not going to contain many elements so it works pretty well, this is how I did it:
When the Page is loaded first time the list is populated and I add an Image attribute which is lost after postback :( so at the time I add the elements with its attributes I create one Session variable "attr" plus the number of the element taken from the "for" cycle (it will be like attr0, attr1, attr2, etc...) and in them I save the value of the attribute (a path to an image in my case), when postback occurs (inside the "else") I just loop the list and add the attribute taken from the Session variable using the "int" of the "for" loop that is the same as when the page was loaded (this is because in this page I do not add elements to the list just selecting so they have always the same index) and the attributes are set again, I hope this helps someone in the future, greetings!
Simple solution is to add the tooltip attributes in the
pre-render
event of the dropdown. Any changes to the state should be done atpre-render
event.sample code :
If you only want to load the listitems on the first load of the page then you will need to enable ViewState so that the control can serialize its state there and reload it when the page posts back.
There are several places where ViewState can be enabled - check the
<pages/>
node in the web.config and also in the<%@ page %>
directive at the top of the aspx file itself for theEnableViewState
property. This setting will need to betrue
for ViewState to work.If you don't want to use ViewState, simply remove the
if (!IsPostBack) { ... }
from around the code that adds theListItems
and the items will be recreated on each postback.Edit: I apologize - I misread your question. You are correct that the attributes do no survive postback as they are not serialized in ViewState. You must re-add those attributes on each postback.
Typical solutions to this problem involves creating new controls that are not quite feasible in normal circumstances. There is a simple yet trivial solution to this problem.
The issue is that the
ListItem
loses its attributes on postback. However, the List itself never loses any custom attributes. One can take advantage of this in a simple yet effective manner thus.Steps:
Serialize your attributes using the code in the answer above (https://stackoverflow.com/a/3099755/3624833)
Store it to a custom attribute of the ListControl (dropdownlist, checklistbox, whatever).
On post back, read back the custom attribute from the ListControl and then deserialize it back as attributes.
Here is the code I used to (de)serialize attributes (What I needed to do was to keep track of what items of the list were originally rendered as selected when retrieved from the backend and then save or delete rows as per the changes made by the user on the UI):
(above, "Users" is a
CheckboxList
control).On post back (in my case a Submit button Click event), I use the below code to retrieve the same and store them into a Dictionary for post processing:
(PS: I have a library funcs that perform error handling and data conversions, omitting the same here for brevity).