developer tip

드롭 다운 목록 제어

copycodes 2020. 11. 17. 08:19
반응형

드롭 다운 목록 제어 asp.net (webforms)의 경우


옵션 그룹을 렌더링 할 수있는 asp.net (3.5)에 대한 드롭 다운 목록 컨트롤을 추천 할 수 있습니까? 감사


나는 과거에 표준 컨트롤을 사용했으며, 특정 위치에서 <optgroup>을 렌더링 할 수 있도록 기본 동작을 재정의 하는 간단한 ControlAdapter추가했습니다 . 추가 기능이 방해가되지 않기 때문에 특별한 동작이 필요하지 않은 컨트롤이있는 경우에도 잘 작동합니다.

이것은 특정 목적을위한 것이며 .Net 2.0으로 작성되었으므로 귀하에게 적합하지 않을 수 있지만 최소한 시작점을 제공해야합니다. 또한 프로젝트에서 .browserfile을 사용하여 연결해야합니다 (예는 게시물 끝 부분 참조).

'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 Sub
End Class

다음은 동일한 클래스의 C # 구현입니다.

/* 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();
    }
}

내 브라우저 파일 이름은 "App_Browsers \ BrowserFile.browser"이며 다음과 같습니다.

<!--
    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>

이 작업을 수행하기 위해 JQuery를 사용했습니다. 먼저 ListItem백엔드의 모든 속성에 대해 새 속성을 추가 한 다음 JQuery wrapAll()메서드 에서 해당 속성을 사용 하여 그룹을 생성했습니다.

씨#:

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("&lt;optgroup label='Less than five'&gt;");
    $("select.listsmall option[@classification='GreaterThanFive']")
        .wrapAll("&lt;optgroup label='Greater than five'&gt;"); 
});

감사합니다 Joel! 모두 ... 원하는 경우 여기에 C # 버전이 있습니다.



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();
    }

}




위의 코드는 옵션 앞에 optgroup에 대한 종료 태그를 렌더링하므로 그룹화를 제대로 나타내지 않는 마크 업에 추가하여 옵션이 들여 쓰기되지 않습니다. 다음은 Tom의 코드를 약간 수정 한 버전입니다.

    public class ExtendedDropDownList : System.Web.UI.WebControls.DropDownList
{
    public const string OptionGroupTag = "optgroup";
    private const string OptionTag = "option";
    protected override void RenderContents(System.Web.UI.HtmlTextWriter writer)
    {
        ListItemCollection items = this.Items;
        int count = items.Count;
        string tag;
        string optgroupLabel;
        if (count > 0)
        {
            bool flag = false;
            string prevOptGroup = null;
            for (int i = 0; i < count; i++)
            {
                tag = OptionTag;
                optgroupLabel = null;
                ListItem item = items[i];
                if (item.Enabled)
                {
                    if (item.Attributes != null && item.Attributes.Count > 0 && item.Attributes[OptionGroupTag] != null)
                    {
                        optgroupLabel = item.Attributes[OptionGroupTag];

                        if (prevOptGroup != optgroupLabel)
                        {
                            if (prevOptGroup != null)
                            {
                                writer.WriteEndTag(OptionGroupTag);
                            }
                            writer.WriteBeginTag(OptionGroupTag);
                            if (!string.IsNullOrEmpty(optgroupLabel))
                            {
                                writer.WriteAttribute("label", optgroupLabel);
                            }
                            writer.Write('>');
                        }
                        item.Attributes.Remove(OptionGroupTag);
                        prevOptGroup = optgroupLabel;
                    }
                    else
                    {
                        if (prevOptGroup != null)
                        {
                            writer.WriteEndTag(OptionGroupTag);
                        }
                        prevOptGroup = null;
                    }

                    writer.WriteBeginTag(tag);
                    if (item.Selected)
                    {
                        if (flag)
                        {
                            this.VerifyMultiSelect();
                        }
                        flag = true;
                        writer.WriteAttribute("selected", "selected");
                    }
                    writer.WriteAttribute("value", item.Value, true);
                    if (item.Attributes != null && item.Attributes.Count > 0)
                    {
                        item.Attributes.Render(writer);
                    }
                    if (optgroupLabel != null)
                    {
                        item.Attributes.Add(OptionGroupTag, optgroupLabel);
                    }
                    if (this.Page != null)
                    {
                        this.Page.ClientScript.RegisterForEventValidation(this.UniqueID, item.Value);
                    }

                    writer.Write('>');
                    HttpUtility.HtmlEncode(item.Text, writer);
                    writer.WriteEndTag(tag);
                    writer.WriteLine();
                    if (i == count - 1)
                    {
                        if (prevOptGroup != null)
                        {
                            writer.WriteEndTag(OptionGroupTag);
                        }
                    }
                }
            }
        }
    }

    protected override object SaveViewState()
    {
        object[] state = new object[this.Items.Count + 1];
        object baseState = base.SaveViewState();
        state[0] = baseState;
        bool itemHasAttributes = false;

        for (int i = 0; i < this.Items.Count; i++)
        {
            if (this.Items[i].Attributes.Count > 0)
            {
                itemHasAttributes = true;
                object[] attributes = new object[this.Items[i].Attributes.Count * 2];
                int k = 0;

                foreach (string key in this.Items[i].Attributes.Keys)
                {
                    attributes[k] = key;
                    k++;
                    attributes[k] = this.Items[i].Attributes[key];
                    k++;
                }
                state[i + 1] = attributes;
            }
        }

        if (itemHasAttributes)
            return state;
        return baseState;
    }

    protected override void LoadViewState(object savedState)
    {
        if (savedState == null)
            return;

        if (!(savedState.GetType().GetElementType() == null) &&
            (savedState.GetType().GetElementType().Equals(typeof(object))))
        {
            object[] state = (object[])savedState;
            base.LoadViewState(state[0]);

            for (int i = 1; i < state.Length; i++)
            {
                if (state[i] != null)
                {
                    object[] attributes = (object[])state[i];
                    for (int k = 0; k < attributes.Length; k += 2)
                    {
                        this.Items[i - 1].Attributes.Add
                            (attributes[k].ToString(), attributes[k + 1].ToString());
                    }
                }
            }
        }
        else
        {
            base.LoadViewState(savedState);
        }
    }
}

다음과 같이 사용하십시오.

            ListItem item1 = new ListItem("option1");
        item1.Attributes.Add("optgroup", "CatA");
        ListItem item2 = new ListItem("option2");
        item2.Attributes.Add("optgroup", "CatA");
        ListItem item3 = new ListItem("option3");
        item3.Attributes.Add("optgroup", "CatB");
        ListItem item4 = new ListItem("option4");
        item4.Attributes.Add("optgroup", "CatB");
        ListItem item5 = new ListItem("NoOptGroup");

        ddlTest.Items.Add(item1);
        ddlTest.Items.Add(item2);
        ddlTest.Items.Add(item3);
        ddlTest.Items.Add(item4);
        ddlTest.Items.Add(item5);

다음은 생성 된 마크 업입니다 (보기 쉽도록 들여 쓰기).

 <select name="ddlTest" id="Select1">
    <optgroup label="CatA">
        <option selected="selected" value="option1">option1</option>
        <option value="option2">option2</option>
    </optgroup>
    <optgroup label="CatB">
        <option value="option3">option3</option>
        <option value="option4">option4</option>
    </optgroup>
    <option value="NoOptGroup">NoOptGroup</option>
 </select>

CodePlexSharp Pieces 프로젝트 는이 (및 기타 여러 가지) 제어 제한을 해결합니다.


반사경을 사용하여 지원되지 않는 이유를 확인합니다. 이유가 있습니다. ListControl의 render 메서드에는 optgroup을 생성하기위한 조건이 없습니다.

protected internal override void RenderContents(HtmlTextWriter writer)
    {
        ListItemCollection items = this.Items;
        int count = items.Count;
        if (count > 0)
        {
            bool flag = false;
            for (int i = 0; i < count; i++)
            {
                ListItem item = items[i];
                if (item.Enabled)
                {
                    writer.WriteBeginTag("option");
                    if (item.Selected)
                    {
                        if (flag)
                        {
                            this.VerifyMultiSelect();
                        }
                        flag = true;
                        writer.WriteAttribute("selected", "selected");
                    }
                    writer.WriteAttribute("value", item.Value, true);
                    if (item.HasAttributes)
                    {
                        item.Attributes.Render(writer);
                    }
                    if (this.Page != null)
                    {
                        this.Page.ClientScript.RegisterForEventValidation(this.UniqueID, item.Value);
                    }
                    writer.Write('>');
                    HttpUtility.HtmlEncode(item.Text, writer);
                    writer.WriteEndTag("option");
                    writer.WriteLine();
                }
            }
        }
    }

그래서 RenderContents 메서드를 재정 의하여 내 드롭 다운 컨트롤을 만듭니다. 내 통제권이 있습니다. 잘 작동하고 있습니다. 나는 Microsoft와 똑같은 코드를 사용하고 옵션이 아닌 optgroup을 생성하기 위해 optgroup 속성을 갖는 listItem을 지원하는 약간의 조건을 추가합니다.

피드백을주세요

public class DropDownListWithOptionGroup : DropDownList
  {
    public const string OptionGroupTag = "optgroup";
    private const string OptionTag = "option";
    protected override void RenderContents(System.Web.UI.HtmlTextWriter writer)
    {
      ListItemCollection items = this.Items;
      int count = items.Count;     
      string tag;
      string optgroupLabel;
      if (count > 0)
      {
        bool flag = false;
        for (int i = 0; i < count; i++)
        {
          tag = OptionTag;
          optgroupLabel = null;
          ListItem item = items[i];
          if (item.Enabled)
          {
            if (item.Attributes != null && item.Attributes.Count > 0 && item.Attributes[OptionGroupTag] != null)
            {
              tag = OptionGroupTag;
              optgroupLabel = item.Attributes[OptionGroupTag];
            }           
            writer.WriteBeginTag(tag);
            // NOTE(cboivin): Is optionGroup
            if (!string.IsNullOrEmpty(optgroupLabel))
            {
              writer.WriteAttribute("label", optgroupLabel);
            }
            else
            {
              if (item.Selected)
              {
                if (flag)
                {
                  this.VerifyMultiSelect();
                }
                flag = true;
                writer.WriteAttribute("selected", "selected");
              }
              writer.WriteAttribute("value", item.Value, true);
              if (item.Attributes != null && item.Attributes.Count > 0)
              {
                item.Attributes.Render(writer);
              }
              if (this.Page != null)
              {
                this.Page.ClientScript.RegisterForEventValidation(this.UniqueID, item.Value);
              }
            }
            writer.Write('>');
            HttpUtility.HtmlEncode(item.Text, writer);
            writer.WriteEndTag(tag);
            writer.WriteLine();
          }
        }
      }

    }
  }

위의 게시물을 기반으로 작업보기 상태로이 컨트롤의 ac # 버전을 만들었습니다.

        public const string OptionGroupTag = "optgroup";
    private const string OptionTag = "option";
    protected override void RenderContents(System.Web.UI.HtmlTextWriter writer)
    {
        ListItemCollection items = this.Items;
        int count = items.Count;
        string tag;
        string optgroupLabel;
        if (count > 0)
        {
            bool flag = false;
            for (int i = 0; i < count; i++)
            {
                tag = OptionTag;
                optgroupLabel = null;
                ListItem item = items[i];
                if (item.Enabled)
                {
                    if (item.Attributes != null && item.Attributes.Count > 0 && item.Attributes[OptionGroupTag] != null)
                    {
                        tag = OptionGroupTag;
                        optgroupLabel = item.Attributes[OptionGroupTag];
                    }
                    writer.WriteBeginTag(tag);
                    // NOTE(cboivin): Is optionGroup
                    if (!string.IsNullOrEmpty(optgroupLabel))
                    {
                        writer.WriteAttribute("label", optgroupLabel);
                    }
                    else
                    {
                        if (item.Selected)
                        {
                            if (flag)
                            {
                                this.VerifyMultiSelect();
                            }
                            flag = true;
                            writer.WriteAttribute("selected", "selected");
                        }
                        writer.WriteAttribute("value", item.Value, true);
                        if (item.Attributes != null && item.Attributes.Count > 0)
                        {
                            item.Attributes.Render(writer);
                        }
                        if (this.Page != null)
                        {
                            this.Page.ClientScript.RegisterForEventValidation(this.UniqueID, item.Value);
                        }
                    }
                    writer.Write('>');
                    HttpUtility.HtmlEncode(item.Text, writer);
                    writer.WriteEndTag(tag);
                    writer.WriteLine();
                }
            }
        }
    }

        protected override object SaveViewState()
    {
        object[] state = new object[this.Items.Count + 1];
        object baseState = base.SaveViewState();
        state[0] = baseState;
        bool itemHasAttributes = false;

        for (int i = 0; i < this.Items.Count; i++)
        {
            if (this.Items[i].Attributes.Count > 0)
            {
                itemHasAttributes = true;
                object[] attributes = new object[this.Items[i].Attributes.Count * 2];
                int k = 0;

                foreach (string key in this.Items[i].Attributes.Keys)
                {
                    attributes[k] = key;
                    k++;
                    attributes[k] = this.Items[i].Attributes[key];
                    k++;
                }
                state[i + 1] = attributes;
            }
        }

        if (itemHasAttributes)
            return state;
        return baseState;
    }

        protected override void LoadViewState(object savedState)
    {
        if (savedState == null)
            return;

        if (!(savedState.GetType().GetElementType() == null) &&
            (savedState.GetType().GetElementType().Equals(typeof(object))))
        {
            object[] state = (object[])savedState;
            base.LoadViewState(state[0]);

            for (int i = 1; i < state.Length; i++)
            {
                if (state[i] != null)
                {
                    object[] attributes = (object[])state[i];
                    for (int k = 0; k < attributes.Length; k += 2)
                    {
                        this.Items[i - 1].Attributes.Add
                            (attributes[k].ToString(), attributes[k + 1].ToString());
                    }
                }
            }
        }
        else
        {
            base.LoadViewState(savedState);
        }
    }

나는 이것이 어떤 사람들에게 도움이되기를 바랍니다 :-)


Irfan의 jQuery 기반 솔루션에 대한보다 일반적인 접근 방식 :

백엔드

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");
...

고객

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 + '">');
});

select 및 optgroup에 대한 외부 반복기와 해당 그룹 내의 항목에 대한 내부 반복기를 사용하여이 작업을 수행했습니다.

<asp:Repeater ID="outerRepeater" runat="server">
    <HeaderTemplate>
        <select id="<%= outerRepeater.ClientID %>">
    </HeaderTemplate>
    <ItemTemplate>
            <optgroup label="<%# Eval("GroupText") %>">
                <asp:Repeater runat="server" DataSource='<%# Eval("Items") %>'>
                    <ItemTemplate>
                        <option value="<%# Eval("Value") %>"><%# Eval("Text") %></option>
                    </ItemTemplate>
                </asp:Repeater>
            </optgroup>
    </ItemTemplate>
    <FooterTemplate>
        </select>
    </FooterTemplate>
</asp:Repeater>

의 데이터 소스 outerRepeater는 다음과 같은 간단한 그룹화입니다.

var data = (from o in thingsToDisplay
            group oby GetAlphaGrouping(o.Name) into g
            orderby g.Key
            select new
            {
                Alpha = g.Key,
                Items = g
            });

그리고 알파 그룹화 문자를 얻으려면 :

private string GetAlphaGrouping(string value)
{
    string firstChar = value.Substring(0, 1).ToUpper();
    int unused;

    if (int.TryParse(firstChar, out unused))
        return "#";

    return firstChar.ToUpper();
}

완벽한 솔루션은 아니지만 작동합니다. 올바른 솔루션은 더 이상 사용 웹폼에, 그러나 우리 MVC 대신합니다. :)


    // How to use:
    // 1. Create items in a select element or asp:DropDownList control
    // 2. Set value of an option or ListItem to "_group_", those will be converted to optgroups
    // 3. On page onload call createOptGroups(domElement), for example like this:
    //    - var lst = document.getElementById('lst');
    //    - createOptGroups(lst, "_group_");
    // 4. You can change groupMarkerValue to anything, I used "_group_"
    function createOptGroups(lst, groupMarkerValue) {
        // Get an array containing the options
        var childNodes = [];
        for (var i = 0; i < lst.options.length; i++)
            childNodes.push(lst.options[i]);

        // Get the selected element so we can preserve selection
        var selectedIndex = lst.selectedIndex;
        var selectedChild = childNodes[selectedIndex];
        var selectedValue = selectedChild.value;

        // Remove all elements
        while (lst.hasChildNodes())
            lst.removeChild(lst.childNodes[0]);

        // Go through the array of options and convert some into groups
        var group = null;
        for (var i = 0; i < childNodes.length; i++) {
            var node = childNodes[i];
            if (node.value == groupMarkerValue) {
                group = document.createElement("optgroup");
                group.label = node.text;
                group.value = groupMarkerValue;
                lst.appendChild(group);
                continue;
            }

            // Add to group or directly under list
            (group == null ? lst : group).appendChild(node);
        }

        // Preserve selected, no support for multi-selection here, sorry
        selectedChild.selected = true;
    }

Chrome 16, Firefox 9 및 IE8에서 테스트되었습니다.


위의 답변과 같이 RenderContents 메서드가 작동합니다. 또한 viewstate를 변경하는 것을 기억해야합니다. UpdatePanels에서 변경되지 않은 viewstate를 사용할 때 문제가 발생했습니다. 여기에는 Sharp Pieces Project 에서 가져온 부분이 있습니다 .

 Protected Overloads Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)
    Dim list As DropDownList = Me

    Dim currentOptionGroup As String
    Dim renderedOptionGroups As New List(Of String)()

    For Each item As ListItem In list.Items
        If item.Attributes("OptionGroup") Is Nothing Then
            RenderListItem(item, writer)
        Else
            currentOptionGroup = item.Attributes("OptionGroup")

            If renderedOptionGroups.Contains(currentOptionGroup) Then
                RenderListItem(item, writer)
            Else
                If renderedOptionGroups.Count > 0 Then
                    RenderOptionGroupEndTag(writer)
                End If

                RenderOptionGroupBeginTag(currentOptionGroup, writer)
                renderedOptionGroups.Add(currentOptionGroup)

                RenderListItem(item, writer)
            End If
        End If
    Next

    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

    writer.Write(HtmlTextWriter.TagRightChar)
    HttpUtility.HtmlEncode(item.Text, writer)
    writer.WriteEndTag("option")
    writer.WriteLine()
End Sub
Protected Overrides Function SaveViewState() As Object
    ' Create an object array with one element for the CheckBoxList's
    ' ViewState contents, and one element for each ListItem in skmCheckBoxList
    Dim state(Me.Items.Count + 1 - 1) As Object 'stupid vb array
    Dim baseState As Object = MyBase.SaveViewState()

    state(0) = baseState
    ' Now, see if we even need to save the view state
    Dim itemHasAttributes As Boolean = False

    For i As Integer = 0 To Me.Items.Count - 1
        If Me.Items(i).Attributes.Count > 0 Then
            itemHasAttributes = True
            ' Create an array of the item's Attribute's keys and values
            Dim attribKV(Me.Items(i).Attributes.Count * 2 - 1) As Object 'stupid vb array
            Dim k As Integer = 0
            For Each key As String In Me.Items(i).Attributes.Keys
                attribKV(k) = key
                k += 1
                attribKV(k) = Me.Items(i).Attributes(key)
                k += 1
            Next
            state(i + 1) = attribKV
        End If
    Next
    ' return either baseState or state, depending on whether or not
    ' any ListItems had attributes
    If (itemHasAttributes) Then
        Return state
    Else
        Return baseState
    End If
End Function


Protected Overrides Sub LoadViewState(ByVal savedState As Object)
    If savedState Is Nothing Then Return
    ' see if savedState is an object or object array
    If Not savedState.GetType.GetElementType() Is Nothing AndAlso savedState.GetType.GetElementType().Equals(GetType(Object)) Then

        ' we have just the base state
        MyBase.LoadViewState(savedState(0))
        'we have an array of items with attributes
        Dim state() As Object = savedState
        MyBase.LoadViewState(state(0))   '/ load the base state
        For i As Integer = 1 To state.Length - 1
            If Not state(i) Is Nothing Then
                ' Load back in the attributes
                Dim attribKV() As Object = state(i)
                For k As Integer = 0 To attribKV.Length - 1 Step +2
                    Me.Items(i - 1).Attributes.Add(attribKV(k).ToString(), attribKV(k + 1).ToString())
                Next
            End If
        Next
    Else
        'load it normal
        MyBase.LoadViewState(savedState)
    End If
End Sub

참고 URL : https://stackoverflow.com/questions/130020/dropdownlist-control-with-optgroups-for-asp-net-webforms

반응형