Элемент управления Dropdownlist с s для asp.net (webforms)?
может ли кто-нибудь порекомендовать элемент управления dropdownlist для asp.net (3.5) что может отображать группы опций? Спасибо
11 ответов:
я использовал стандартный элемент управления в прошлом, и просто добавил простой 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.браузер " и выглядел так:
<!-- 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
из бэкэнда, а затем использовал этот атрибут в JQuerywrapAll()
метод создания группы...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'>"); });
Спасибо Джоэль! каждый... вот версия 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 перед любым из параметров, поэтому параметры не получают отступы, как они должны в дополнение к разметке, неправильно представляющей группировку. Вот моя слегка измененная версия кода Тома:
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>
The проект Sharp Pieces на CodePlex решает это (и несколько других) ограничения управления.
Я использую отражатель, чтобы увидеть, почему не поддерживается. Вот почему. В методе render элемента управления ListControl нет условия для создания 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, просто добавьте небольшое условие для поддержки 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(); } } } } }
на основе сообщений выше я создал версию c# этого элемента управления с рабочим состоянием представления.
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); } }
Я надеюсь, что это помогает некоторым людям :-)
более общий подход к Ирфан это решение на основе jQuery:
backend
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 и optgroups и внутреннего ретранслятора для элементов в этой группе:
<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, работают. Вы также должны помнить, чтобы изменить отображение. Я пришел в проблему при использовании не измененного состояния представления в UpdatePanels. Это имеет части, взятые из Острые Куски Проекта.
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