1

I have manually add some addition attirubte during dropdownlist databound event. However, after postback the attribute is missing. And i found related issue at ListItems attributes in a DropDownList are lost on postback? and i follow exactly the solution.

This is what i have

Dropdownlist databound event *.aspx.vb, I add in addition attribute "class" into every listitem

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    If Not IsPostBack Then
        ddlCountry.DataBind()
    End If
End Sub

Protected Sub ddlCountry_DataBound(ByVal sender As Object, ByVal e As System.EventArgs) Handles ddlCountry.DataBound
    Dim ddlCountryList As DropDownList = LocationBLL.GetDropDownList("Country", "C", "C", False, "")
    Dim lstPleaseSelect As ListItem = New ListItem("Please Select", "-1")
    Dim lstOthers As ListItem = New ListItem("Others", "0")

    lstPleaseSelect.Attributes("class") = "-1"
    lstOthers.Attributes("class") = "-1"

    ddlCountry.Items.Add(lstPleaseSelect)
    For Each lstItem As ListItem In ddlCountryList.Items
        lstItem.Attributes("class") = lstItem.Value
        ddlCountry.Items.Add(lstItem)
    Next
    ddlCountry.Items.Add(lstOthers)
End Sub

*.aspx

<%@ Register TagPrefix="msjNewControls" Namespace="NewControls"%>

*.aspx

<msjNewControls:NewDropDownList ID="ddlCountry" runat="server" AutoPostBack="False" >
</msjNewControls:NewDropDownList>

class file *.vb

Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Security.Permissions
Imports System.Linq
Imports System.Text
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls

Namespace NewControls
<DefaultProperty("Text")> _
<ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1>")> _
Public Class NewDropDownList
    Inherits DropDownList

    <Bindable(True)> _
    <Category("Appearance")> _
    <DefaultValue("")> _
    <Localizable(True)> _
    Protected Overrides Function SaveViewState() As Object
        ' create object array for Item count + 1
        Dim allStates As Object() = New Object(Me.Items.Count) {}

        ' the +1 is to hold the base info
        Dim baseState As Object = MyBase.SaveViewState()
        allStates(0) = baseState

        Dim i As Int32 = 1
        ' now loop through and save each Style attribute for the List
        For Each li As ListItem In Me.Items
            Dim j As Int32 = 0
            Dim attributes As String()() = New String(li.Attributes.Count - 1)() {}
            For Each attribute As String In li.Attributes.Keys
                attributes(System.Math.Max(System.Threading.Interlocked.Increment(j), j - 1)) = New String() {attribute, li.Attributes(attribute)}
            Next
            allStates(System.Math.Max(System.Threading.Interlocked.Increment(i), i - 1)) = attributes
        Next
        Return allStates
    End Function

    Protected Overrides Sub LoadViewState(ByVal savedState As Object)
        If savedState IsNot Nothing Then
            Dim myState As Object() = DirectCast(savedState, Object())

            ' restore base first
            If myState(0) IsNot Nothing Then
                MyBase.LoadViewState(myState(0))
            End If

            Dim i As Int32 = 1
            For Each li As ListItem In Me.Items
                ' loop through and restore each style attribute
                For Each attribute As String() In DirectCast(myState(System.Math.Max(System.Threading.Interlocked.Increment(i), i - 1)), String()())
                    li.Attributes(attribute(0)) = attribute(1)
                Next
            Next
        End If
    End Sub
End Class
End Namespace

However i still received below error in my class file.

Exception Details: System.InvalidCastException: Unable to cast object of type 'System.Collections.DictionaryEntry' to type 'System.Web.UI.WebControls.ListItem'.

Source Error: 

Line 34:                     attributes(System.Math.Max(System.Threading.Interlocked.Increment(j), j - 1)) = New String() {attribute, li.Attributes(attribute)}

Source File: D:\root\App_Code\BLL\CustomDropDownListBLL.vb    Line: 34 

Anyone can help?

Community
  • 1
  • 1
My2ndLovE
  • 397
  • 4
  • 18

1 Answers1

0

I found that the only values in a ddl that are persisted are the text and value. So, I wrote the following code to keep color coding and bolding list items that are marked by the user to be high priority. This worked for me in the SelectedIndexChanged event. Since the HighPriority flag is stored in SQL, i set the first character of the ListItem text to an ! when returning the data rows. Also, I found that when an item is selected that the Forecolor attribute still would not apply, so i used the bSetSelected flag to set the ForeColor to the appropriate color as needed.

    Private Sub ddlYourDropDownList_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ddlYourDropDownList.SelectedIndexChanged

    Try
        'do your processing here, then reset the attributes below

        'color code high priority requests in Red
        Dim li As ListItem, bSetSelected As Boolean = False
        For Each li In ddlYourDropDownList.Items
            'see if this is a High Priority item, SQL Proc places the ! at the start of the string
            If li.Text.Substring(0, 1) = "!" Then
                li.Attributes.Add("style", "color:Red; font-weight: bold;")
                'once we set the selected one, no need to change ForeColor anymore
                If Not bSetSelected Then
                    If li.Selected Then
                        ddlYourDropDownList.ForeColor = Drawing.Color.Red
                        bSetSelected = True
                    Else
                        ddlYourDropDownList.ForeColor = Drawing.Color.Black
                    End If
                End If
            Else
                li.Attributes.Add("style", "color:Black; font-weight: normal;")
            End If
        Next


    Catch ex As Exception
        lblMessage.Text = "Error: " & ex.Message
    End Try
End Sub
SQL_Yoda
  • 1
  • 1