创建一个带分组功能的下拉列表框控件
这是http://www.codeplex.com/上的一个开源项目SharpPieces , 不过作者目前只开发了这一个控件, 实现了页面PostBack后保存控件状态 .分享一下 .
效果如图:
源码下载地址: 点击查看
http://www.codeplex.com/SharpPieces/Release/ProjectReleases.aspx?ReleaseId=6782
源代码如下 作者有详细的注释
复制
保存
使用方法:
复制
保存
效果如图:

源码下载地址: 点击查看
http://www.codeplex.com/SharpPieces/Release/ProjectReleases.aspx?ReleaseId=6782
源代码如下 作者有详细的注释

using System; using System.Collections.Generic; using System.Text; using System.Web.UI.WebControls; using System.Web; namespace ASPNETControls { public class OptgroupCombobox : DropDownList { private const string optGroupAttributeKey = "optgroup"; /// <summary> /// Override the SaveViewState to save the control's Attributes /// </summary> /// <returns></returns> protected override object SaveViewState() { // Create an object array with one element for the CheckBoxList's // ViewState contents, and one element for each ListItem in skmCheckBoxList object[] state = new object[this.Items.Count + 1]; object baseState = base.SaveViewState(); state[0] = baseState; // Now, see if we even need to save the view state bool itemHasAttributes = false; for (int i = 0; i < this.Items.Count; i++) { if (this.Items[i].Attributes.Count > 0) { itemHasAttributes = true; // Create an array of the item's Attribute's keys and values object[] attribKV = new object[this.Items[i].Attributes.Count * 2]; int k = 0; foreach (string key in this.Items[i].Attributes.Keys) { attribKV[k++] = key; attribKV[k++] = this.Items[i].Attributes[key]; } state[i + 1] = attribKV; } } // return either baseState or state, depending on whether or not // any ListItems had attributes if (itemHasAttributes) return state; else return baseState; } /// <summary> /// Override the LoadViewState to load the control's Attributes /// </summary> protected override void LoadViewState(object savedState) { if (savedState == null) return; // see if savedState is an object or object array if (savedState is object[]) { // we have an array of items with attributes object[] state = (object[]) savedState; base.LoadViewState(state[0]); // load the base state for (int i = 1; i < state.Length; i++) { if (state[i] != null) { // Load back in the attributes object[] attribKV = (object[]) state[i]; for (int k = 0; k < attribKV.Length; k += 2) this.Items[i - 1].Attributes.Add(attribKV[k].ToString(), attribKV[k + 1].ToString()); } } } else // we have just the base state base.LoadViewState(savedState); } protected override void RenderContents(System.Web.UI.HtmlTextWriter writer) { if (this.Items.Count > 0) { bool selected = false; bool optGroupStarted = false; for (int i = 0; i < this.Items.Count; i++) { ListItem item = this.Items[i]; if (item.Enabled) { if (item.Attributes[optGroupAttributeKey] != null) { if (optGroupStarted) writer.WriteEndTag("optgroup"); writer.WriteBeginTag("optgroup"); writer.WriteAttribute("label", item.Text); writer.Write('>'); writer.WriteLine(); optGroupStarted = true; } else { writer.WriteBeginTag("option"); if (item.Selected) { if (selected) { this.VerifyMultiSelect(); } selected = true; writer.WriteAttribute("selected", "selected"); } writer.WriteAttribute("value", item.Value, true); if (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("option"); writer.WriteLine(); } } } if (optGroupStarted) writer.WriteEndTag(optGroupAttributeKey); } } /// <summary> /// Adds a optgroup element. /// </summary> public void AddGroup(string text) { ListItem li = new ListItem(); li.Text = text; li.Attributes[optGroupAttributeKey] = "1"; this.Items.Add(li); } } }
使用方法:

this.cboTest.Items.Add("Choose an item"); this.cboTest.AddGroup("Computers"); this.cboTest.Items.Add("Monitor"); this.cboTest.Items.Add("Mouse"); this.cboTest.Items.Add("Keyboard"); this.cboTest.AddGroup("Phones"); this.cboTest.Items.Add("iPhone"); this.cboTest.Items.Add("gPhone");