Dropdownlist control with <optgroup>s for asp.net (webforms)? Dropdownlist control with <optgroup>s for asp.net (webforms)? asp.net asp.net

Dropdownlist control with <optgroup>s for asp.net (webforms)?


I've used the standard control in the past, and just added a simple ControlAdapter for it that would override the default behavior so it could render <optgroup>s in certain places. This works great even if you have controls that don't need the special behavior, because the additional feature doesn't get in the way.

Note that this was for a specific purpose and written in .Net 2.0, so it may not suit you as well, but it should at least give you a starting point. Also, you have to hook it up using a .browserfile in your project (see the end of the post for an example).

'This codes makes the dropdownlist control recognize items with "--"'for the label or items with an OptionGroup attribute and render them'as <optgroup> instead of <option>.Public Class DropDownListAdapter    Inherits System.Web.UI.WebControls.Adapters.WebControlAdapter    Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)        Dim list As DropDownList = Me.Control        Dim currentOptionGroup As String        Dim renderedOptionGroups As New Generic.List(Of String)        For Each item As ListItem In list.Items            Page.ClientScript.RegisterForEventValidation(list.UniqueID, item.Value)            If item.Attributes("OptionGroup") IsNot Nothing Then                'The item is part of an option group                currentOptionGroup = item.Attributes("OptionGroup")                If Not renderedOptionGroups.Contains(currentOptionGroup) Then                    'the header was not written- do that first                    'TODO: make this stack-based, so the same option group can be used more than once in longer select element (check the most-recent stack item instead of anything in the list)                    If (renderedOptionGroups.Count > 0) Then                        RenderOptionGroupEndTag(writer) 'need to close previous group                    End If                    RenderOptionGroupBeginTag(currentOptionGroup, writer)                    renderedOptionGroups.Add(currentOptionGroup)                End If                RenderListItem(item, writer)            ElseIf item.Text = "--" Then 'simple separator                RenderOptionGroupBeginTag("--", writer)                RenderOptionGroupEndTag(writer)            Else                'default behavior: render the list item as normal                RenderListItem(item, writer)            End If        Next item        If renderedOptionGroups.Count > 0 Then            RenderOptionGroupEndTag(writer)        End If    End Sub    Private Sub RenderOptionGroupBeginTag(ByVal name As String, ByVal writer As HtmlTextWriter)        writer.WriteBeginTag("optgroup")        writer.WriteAttribute("label", name)        writer.Write(HtmlTextWriter.TagRightChar)        writer.WriteLine()    End Sub    Private Sub RenderOptionGroupEndTag(ByVal writer As HtmlTextWriter)        writer.WriteEndTag("optgroup")        writer.WriteLine()    End Sub    Private Sub RenderListItem(ByVal item As ListItem, ByVal writer As HtmlTextWriter)        writer.WriteBeginTag("option")        writer.WriteAttribute("value", item.Value, True)        If item.Selected Then            writer.WriteAttribute("selected", "selected", False)        End If        For Each key As String In item.Attributes.Keys            writer.WriteAttribute(key, item.Attributes(key))        Next key        writer.Write(HtmlTextWriter.TagRightChar)        HttpUtility.HtmlEncode(item.Text, writer)        writer.WriteEndTag("option")        writer.WriteLine()    End SubEnd Class

Here's a C# implementation of the same Class:

/* This codes makes the dropdownlist control recognize items with "--" * for the label or items with an OptionGroup attribute and render them * as <optgroup> instead of <option>. */public class DropDownListAdapter : WebControlAdapter{    protected override void RenderContents(HtmlTextWriter writer)    {        //System.Web.HttpContext.Current.Response.Write("here");        var list = (DropDownList)this.Control;        string currentOptionGroup;        var renderedOptionGroups = new List<string>();        foreach (ListItem item in list.Items)        {            Page.ClientScript.RegisterForEventValidation(list.UniqueID, item.Value);            //Is the item part of an option group?            if (item.Attributes["OptionGroup"] != null)            {                currentOptionGroup = item.Attributes["OptionGroup"];                //Was the option header already written, then just render the list item                if (renderedOptionGroups.Contains(currentOptionGroup))                    RenderListItem(item, writer);                //The header was not written,do that first                else                {                    //Close previous group                    if (renderedOptionGroups.Count > 0)                        RenderOptionGroupEndTag(writer);                    RenderOptionGroupBeginTag(currentOptionGroup, writer);                    renderedOptionGroups.Add(currentOptionGroup);                    RenderListItem(item, writer);                }            }            //Simple separator            else if (item.Text == "--")            {                RenderOptionGroupBeginTag("--", writer);                RenderOptionGroupEndTag(writer);            }            //Default behavior, render the list item as normal            else                RenderListItem(item, writer);        }        if (renderedOptionGroups.Count > 0)            RenderOptionGroupEndTag(writer);    }    private void RenderOptionGroupBeginTag(string name, HtmlTextWriter writer)    {        writer.WriteBeginTag("optgroup");        writer.WriteAttribute("label", name);        writer.Write(HtmlTextWriter.TagRightChar);        writer.WriteLine();    }    private void RenderOptionGroupEndTag(HtmlTextWriter writer)    {        writer.WriteEndTag("optgroup");        writer.WriteLine();    }    private void RenderListItem(ListItem item, HtmlTextWriter writer)    {        writer.WriteBeginTag("option");        writer.WriteAttribute("value", item.Value, true);        if (item.Selected)            writer.WriteAttribute("selected", "selected", false);        foreach (string key in item.Attributes.Keys)            writer.WriteAttribute(key, item.Attributes[key]);        writer.Write(HtmlTextWriter.TagRightChar);        HttpUtility.HtmlEncode(item.Text, writer);        writer.WriteEndTag("option");        writer.WriteLine();    }}

My browser file was named "App_Browsers\BrowserFile.browser" and looked like this:

<!--    You can find existing browser definitions at    <windir>\Microsoft.NET\Framework\<ver>\CONFIG\Browsers--><browsers>   <browser refID="Default">      <controlAdapters>        <adapter controlType="System.Web.UI.WebControls.DropDownList"                adapterType="DropDownListAdapter" />      </controlAdapters>   </browser></browsers>


I have used JQuery to achieve this task. I first added an new attribute for every ListItem from the backend and then used that attribute in JQuery wrapAll() method to create groups...

C#:

foreach (ListItem item in ((DropDownList)sender).Items){    if (System.Int32.Parse(item.Value) < 5)        item.Attributes.Add("classification", "LessThanFive");    else        item.Attributes.Add("classification", "GreaterThanFive");} 

JQuery:

$(document).ready(function() {    //Create groups for dropdown list    $("select.listsmall option[@classification='LessThanFive']")        .wrapAll("<optgroup label='Less than five'>");    $("select.listsmall option[@classification='GreaterThanFive']")        .wrapAll("<optgroup label='Greater than five'>"); });


Thanks Joel! everyone... here's C# version if you want it:

using System;using System.Web.UI.WebControls.Adapters;using System.Web.UI;using System.Web.UI.WebControls;using System.Collections.Generic;using System.Web;//This codes makes the dropdownlist control recognize items with "--"'//for the label or items with an OptionGroup attribute and render them'//as  instead of .'public class DropDownListAdapter : WebControlAdapter{    protected override void RenderContents(HtmlTextWriter writer)    {        DropDownList list = Control as DropDownList;        string currentOptionGroup;        List renderedOptionGroups = new List();        foreach(ListItem item in list.Items)        {            if (item.Attributes["OptionGroup"] != null)            {                //'The item is part of an option group'                currentOptionGroup = item.Attributes["OptionGroup"];                //'the option header was already written, just render the list item'                if(renderedOptionGroups.Contains(currentOptionGroup))                    RenderListItem(item, writer);                else                {                    //the header was not written- do that first'                    if (renderedOptionGroups.Count > 0)                        RenderOptionGroupEndTag(writer); //'need to close previous group'                    RenderOptionGroupBeginTag(currentOptionGroup, writer);                    renderedOptionGroups.Add(currentOptionGroup);                    RenderListItem(item, writer);                }            }            else if (item.Text == "--") //simple separator            {                RenderOptionGroupBeginTag("--", writer);                RenderOptionGroupEndTag(writer);            }            else            {                //default behavior: render the list item as normal'                RenderListItem(item, writer);            }        }        if(renderedOptionGroups.Count > 0)            RenderOptionGroupEndTag(writer);    }    private void RenderOptionGroupBeginTag(string name, HtmlTextWriter writer)    {        writer.WriteBeginTag("optgroup");        writer.WriteAttribute("label", name);        writer.Write(HtmlTextWriter.TagRightChar);        writer.WriteLine();    }    private void RenderOptionGroupEndTag(HtmlTextWriter writer)    {        writer.WriteEndTag("optgroup");        writer.WriteLine();    }    private void RenderListItem(ListItem item, HtmlTextWriter writer)    {        writer.WriteBeginTag("option");        writer.WriteAttribute("value", item.Value, true);        if (item.Selected)            writer.WriteAttribute("selected", "selected", false);        foreach (string key in item.Attributes.Keys)            writer.WriteAttribute(key, item.Attributes[key]);        writer.Write(HtmlTextWriter.TagRightChar);        HttpUtility.HtmlEncode(item.Text, writer);        writer.WriteEndTag("option");        writer.WriteLine();    }}