Tuesday, October 18, 2011

Add the optgroup tag to your DropDownList

Problem: The asp.net DropDownList control does not support rendering of the optgroup tag (it will only generate option tags).

Solution: Once again, a bit like trying to get the validation controls to use the display:block style when its display is set to dynamic, sometimes it can be tough to bend asp.net to do what you want when it isn't supported out of the box.


Your options seem to be:

1. Use an adapter to change the html that the asp.net DropDownList control renders (affects all DropDownLists in your solution).
2. Inherit from the DropDownList and change the html that your new control renders.
3. Use javascript to do some magic once the control has rendered.
4. Don't use optgroup - depending on your scenario, it may not be the best UI solution.

I went with option 1. and a lot of trial and error based on various examples on the net. My main problem was that there weren't enough complete code solutions showing all the bits of code and how to use it.

The examples I tried from the stackoverflow page ended up giving me the following error when I tried submitting the page:

Invalid postback or callback argument. Event validation is enabled using ...
I didn't have time to investigate so I went with a different example. In the end the best example I found came from Christoff Truter: http://www.cstruter.com/blog/259. The only clarifications: Step 3 should all be within:
public class DropDownListAdapter : WebControlAdapter
{
...
}
In the overridden version of OnLoad in Step 3, you need to add a null check before setting the Group attribute value (in case you have provided a listelement in your dropdownlist without the "Group" attribute e.g. a blank 'please select a value' item). i.e.
if (groups[i] != null)
{
dropDownList.Items[i].Attributes["Group"] = groups[i].ToString();
}
The final piece of the puzzle was how to create your DropDownList. The big gotcha was that I couldn't use DataSource/DataBind because when I did I lost the attribute that I had set on the listitems (perhaps it was because of the issue described here: http://www.4guysfromrolla.com/articles/091405-1.aspx). This was my code (if you have a way to get DataSource/DataBind working let me know).

protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
//Find all currently open clubs which have indicated that they provide X-Service
List currentXServiceClubs = DBHelper.GetAllCurrentClubsOfferingXService();

//Create list with the custom "Group" attribute
List listItemsForCurrentXServiceClubs = new List();

lstXServiceClubs.Items.Add("");
foreach (var club in currentXServiceClubs)
{
ListItem newListItem = new ListItem();
newListItem.Attributes.Add("Group", club.State);
newListItem.Text = club.CentreName;
newListItem.Value = club.CentreID.ToString();
lstXServiceClubs.Items.Add(newListItem);
//NOTE: If you use the DataSource / DataBind notation then
//the custom attribute will not be passed through to the DropDownListAdapter
//and hence you will lose the OptGroup functionality. As a future project
//review if there is a way around this.
}
}
}



No comments:

Post a Comment