函数式编程
我过去使用过标准控件,只是为其添加了一个简单的ControlAdapter,它将覆盖默认行为,因此它可以在某些位置呈现<optgroup>。即使您的控件不需要特殊的行为,这也能很好地工作,因为附加功能不会妨碍您。请注意,这是出于特定目的并用.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 SubEnd 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>
扬帆大鱼
这里是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(); }}