Nic*_*ick 65 asp.net webforms custom-server-controls drop-down-menu
任何人都可以推荐一个可以渲染选项组的asp.net(3.5)的下拉列表控件吗?谢谢
Joe*_*orn 47
我以前使用过标准控件,只是为它添加了一个简单的ControlAdapter,它会覆盖默认行为,因此它可以在某些地方呈现<optgroup>.即使您有不需要特殊行为的控件,这也很有效,因为附加功能不会妨碍.
请注意,这是出于特定目的并使用.Net 2.0编写的,因此它可能也不适合您,但它至少应该为您提供一个起点.此外,您必须使用项目中的.browser文件将其连接起来(有关示例,请参阅帖子的结尾).
'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
Run Code Online (Sandbox Code Playgroud)
这是同一个类的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();
}
}
Run Code Online (Sandbox Code Playgroud)
我的浏览器文件名为"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>
Run Code Online (Sandbox Code Playgroud)
小智 26
我用JQuery来完成这个任务.我首先为ListItem后端添加了一个新属性,然后在JQuery wrapAll()方法中使用该属性来创建组...
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");
}
Run Code Online (Sandbox Code Playgroud)
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'>");
});
Run Code Online (Sandbox Code Playgroud)
Nic*_*ina 20
谢谢乔尔!大家......如果你需要,这里是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();
}
}
Run Code Online (Sandbox Code Playgroud)
nw.*_*nw. 19
上面的代码在任何选项之前呈现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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
像这样使用它:
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);
Run Code Online (Sandbox Code Playgroud)
这是生成的标记(缩进以便于查看):
<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>
Run Code Online (Sandbox Code Playgroud)
我用反射器来看看为什么不支持.这就是原因.在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();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以我创建了自己的下拉控件,重写方法RenderContents.有我的控制权.工作正常.我使用完全相同的Microsoft代码,只需添加一些条件来支持listItem,它具有属性optgroup来创建一个optgroup而不是一个选项.
给我一些反馈
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();
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
基于上面的帖子,我创建了具有工作视图状态的此控件的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);
}
}
Run Code Online (Sandbox Code Playgroud)
我希望这可以帮助一些人:-)
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");
...
Run Code Online (Sandbox Code Playgroud)
客户
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 + '">');
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
48941 次 |
| 最近记录: |