How can I add option groups in ASP.NET drop down list?

This is old but since I used the accepted answer recently I wanted to share my experience with it. While it does provide the correct markup, it caused problems for me, specifically whenever I tried to submit a form with any dropdownlist I would get the dreaded "Invalid postback or callback argument" error. After googling like a maniac, I came across this article which then links to this blog post. The code I ended up using was this:

    public class DropDownListAdapter : System.Web.UI.WebControls.Adapters.WebControlAdapter {
    protected override void RenderContents(HtmlTextWriter writer) {

        var dropDownList = (DropDownList)Control;
        var items = dropDownList.Items;

        var groups = (from p in items.OfType<ListItem>()
                      group p by p.Attributes["Group"] into g
                      select new { Label = g.Key, Items = g.ToList() });

        foreach (var group in groups)
        {
            if (!String.IsNullOrEmpty(group.Label))
            {
                writer.WriteBeginTag("optgroup");
                writer.WriteAttribute("label", group.Label);
                writer.Write(">");
            }

            var count = group.Items.Count();
            if (count > 0)
            {
                var flag = false;
                for (var i = 0; i < count; i++)
                {
                    var item = group.Items[i];

                    writer.WriteBeginTag("option");
                    if (item.Selected)
                    {
                        if (flag)
                        {
                            throw new HttpException("Multiple selected items not allowed");
                        }
                        flag = true;

                        writer.WriteAttribute("selected", "selected");
                    }

                    if (!item.Enabled)
                    {
                        writer.WriteAttribute("disabled", "true");
                    }

                    writer.WriteAttribute("value", item.Value, true);

                    if (Page != null)
                    {
                        Page.ClientScript.RegisterForEventValidation(dropDownList.UniqueID, item.Value);
                    }
                    writer.Write('>');
                    HttpUtility.HtmlEncode(item.Text, writer);
                    writer.WriteEndTag("option");
                    writer.WriteLine();
                }
            }
            if (!String.IsNullOrEmpty(group.Label))
            {
                writer.WriteEndTag("optgroup");
            }
        }
    }
}

The listitems used here are created in the design page rather than the code-behind page like so:

<asp:ListItem Value="apple" Text="Apple" Group="Fruit"></asp:ListItem>
<asp:ListItem Value="banana" Text="Banana" Group="Fruit"></asp:ListItem>
<asp:ListItem Value="asparagus" Text="Asparagus" Group="Vegetable"></asp:ListItem>
<asp:ListItem Value="eggs" Text="Eggs" Group="Dairy"></asp:ListItem>

This produced the same markup as the accepted answer here but this didn't give me the postback error. I hope this saves someone some grief.


I really like this client-side solution (doesn't need a custom DropDownList, but uses jQuery):

backend

private void _addSelectItem(DropDownList list, string title, string value, string group = null) {
   ListItem item = new ListItem(title, value);
   if (!String.IsNullOrEmpty(group))
   {
       item.Attributes["data-category"] = group;
   }
   list.Items.Add(item);
}

...
_addSelectItem(dropDown, "Option 1", "1");
_addSelectItem(dropDown, "Option 2", "2", "Category");
_addSelectItem(dropDown, "Option 3", "3", "Category");
...

client

var groups = {};
$("select option[data-category]").each(function () {
     groups[$.trim($(this).attr("data-category"))] = true;
});
$.each(groups, function (c) {
     $("select option[data-category='"+c+"']").wrapAll('<optgroup label="' + c + '">');
});

Check out this article, I too had need for Group DropDown list . . .

ASP.NET DropDownList with OptionGroup support

Usage :

protected void Page_Load(object sender, EventArgs e) 
{

              ListItem item1 = new ListItem("Camel", "1");
              item1.Attributes["OptionGroup"] = "Mammals";

              ListItem item2 = new ListItem("Lion", "2");
              item2.Attributes["OptionGroup"] = "Mammals";

              ListItem item3 = new ListItem("Whale", "3");
              item3.Attributes["OptionGroup"] = "Mammals";

              ListItem item4 = new ListItem("Walrus", "4");
              item4.Attributes["OptionGroup"] = "Mammals";

              ListItem item5 = new ListItem("Velociraptor", "5");
              item5.Attributes["OptionGroup"] = "Dinosaurs";

              ListItem item6 = new ListItem("Allosaurus", "6");
              item6.Attributes["OptionGroup"] = "Dinosaurs";

              ListItem item7 = new ListItem("Triceratops", "7");
              item7.Attributes["OptionGroup"] = "Dinosaurs";

              ListItem item8 = new ListItem("Stegosaurus", "8");
              item8.Attributes["OptionGroup"] = "Dinosaurs";

              ListItem item9 = new ListItem("Tyrannosaurus", "9");
              item9.Attributes["OptionGroup"] = "Dinosaurs";


              ddlItems.Items.Add(item1);
              ddlItems.Items.Add(item2);
              ddlItems.Items.Add(item3);
              ddlItems.Items.Add(item4);
              ddlItems.Items.Add(item5);
              ddlItems.Items.Add(item6);
              ddlItems.Items.Add(item7);
              ddlItems.Items.Add(item8);
              ddlItems.Items.Add(item9);

          }

Tags:

C#

Asp.Net