Click here to Skip to main content
Click here to Skip to main content

Creating a BulletedList control to replace the asp:BulletedList

, 17 Jul 2008 CPOL
Rate this:
Please Sign up or sign in to vote.
I needed a simple control to display a bulleted list based on a strongly typed list of strings.

Introduction

I wanted to display a bulleted list of items (<li> tags rendered within a <ul> tag) on a web page, based on a strongly typed list of string objects which I had gathered from some data source.

I noticed that there is a BulletedList control available in .NET, so I tried it. I set the DataSource to my List(Of String) and called DataBind().

It worked — sort of. The bulleted list displayed the content of each string in my list, but it insisted on HTML-encoding every item. As I had hyperlinks within the list (<a href="somepage.htm">click me</a>), it was rendering to the output stream as &lt;a href="somepage.htm"&gt;click me&lt;/a&gt; such that I did not get a hyperlink in the page. Frustrating. Thanks for that auto-encoding, Microsoft!

Background

I spent a little while looking into the BulletedList control and Googling this problem, but it seemed to be just a "feature" of the BulletedList which wasn't controllable (I might be wrong!). Instead of using the asp:BulletedList, I wrote a Repeater to render out the items, but it looked messy in the .aspx page, and I wasn't really happy with it — I wanted a control as I wanted to use it in a few places — a Repeater might have been OK for just one instance, but not several.

I threw my hands up at another short-sighted "feature" of the framework, and went out to enjoy a meatball sub and oatmeal and raisin cookie, with a diet coke on the side.

In the sandwich shop, whilst watching the July rain driving at the pavements outside, I decided to just write a control myself to do what I wanted — I thought I had quite a basic requirement here, and decided that in the time I spent Googling for the solution, I could have solved it myself. Now, all I had to do was get back across the road to the office, in a short sleeved shirt, in the pouring rain. I love Manchester.

Developing the Code

My first step was to create a .vb class file, which I called BulletedList.vb. I put the class inside a namespace to make it easy to register it later on, and made it inherit from Control.

Next, I created a property called "Items" which provides read/write access to the list of items I wanted to render. Remember, I wanted to use a strongly typed list of strings. I save the items within the ViewState of the control.

        Public Property Items() As List(Of String)
            Get
                If IsNothing(ViewState("Items")) Then
                    ' Instantiate the list of items to a new list; which will allow us to do ".Items.Add" from elsewhere in code without 
                    ' having to worry about null values checks.
                    ViewState("Items") = New list(Of String)
                End If
                Return DirectCast(ViewState("Items"), List(Of String))
            End Get
            Set(ByVal value As List(Of String))
                ViewState("Items") = value
            End Set
        End Property

So, I can now hold a list of the strings I want to display on the page. The next thing is to tell the control how it should render them. I simply overrode the "Render" method of the control, and provided some custom logic:

        Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
            ' Only output something if there are items in the collection:
            If Items.Count > 0 Then
                ' Output start tag <ul>
                writer.RenderBeginTag(HtmlTextWriterTag.Ul)

                ' Output all the items
                For Each s As String In Items
                    writer.RenderBeginTag(HtmlTextWriterTag.Li)
                   
                    writer.Write(s)
                    writer.RenderEndTag()

                    writer.WriteLine()
                Next

                ' Output end tag </ul>

                writer.RenderEndTag()
            End If

            MyBase.Render(writer)
        End Sub

As you can see, it is reasonably straightforward. If there are any items in the list, then I create the opening <ul> tag, and then write out each item contained within <li> tags. Once all the items have been written, I close the <ul> tag, and call the base Render method (it doesn't actually do anything, it's just there for completeness).

HTML Encoding the Text

I appreciate the sentiment of HTML-encoding the text from a security point of view; that HTML data retrieved from data stores (especially where that data has come from an unknown source) should always be HTML-encoded before it is displayed out onto web pages to help prevent injection attacks.

For this reason, I provided another property, EncodeHtml, to allow the user of the control to decide whether they want the output to be encoded before it gets rendered. The property is a simple boolean value saved in the ViewState:

        Public Property EncodeHtml() As Boolean
            Get
                If IsNothing(ViewState("EncodeHtml")) Then
                    Return False
                Else
                    Return DirectCast(ViewState("EncodeHtml"), Boolean)
                End If
            End Get
            Set(ByVal value As Boolean)
                ViewState("EncodeHtml") = value
            End Set
        End Property

I then amended the Render method to take account of this property, and HTML-encode the text if desired. This concludes the control's implementation.

        Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
            ' Only output something if there are items in the collection:
            If Items.Count > 0 Then
                ' Output start tag <ul>
                writer.RenderBeginTag(HtmlTextWriterTag.Ul)

                ' Output all the items
                For Each s As String In Items
                    writer.RenderBeginTag(HtmlTextWriterTag.Li)
                    If EncodeHtml Then
                        writer.Write(HttpContext.Current.Server.HtmlEncode(s))
                    Else
                        writer.Write(s)
                    End If
                    writer.RenderEndTag()

                    writer.WriteLine()
                Next

                ' Output end tag </ul>

                writer.RenderEndTag()
            End If

            MyBase.Render(writer)
        End Sub

Using the Code

Using the code is simple. First, register the control at the top of the .aspx file:

<%@ Register TagPrefix="SCC" Namespace="SCC.WebUserControls" %>

Next, add the control into the .aspx markup where you want the bulleted list to appear:

<SCC:BulletedList ID="blHyperlinks" runat="server" /> <!--<span class="code-comment"> Render all items "as-is" --></span>

<SCC:BulletedList ID="blSafeHtml" runat="server" EncodeHtml="true" /> <!--<span class="code-comment"> Encode HTML --></span>

Finally, in Page_Load or similar, bind the control to your desired list of strings:

Dim Hyperlinks As New List(Of String)
Me.blHyperlinks.Items = Hyperlinks

and that's it. "Should just work".

The downloadable file contains a fully XML-commented code listing for your perusal. Any comments welcome (particularly, if you can tell me whether the asp:BulletedList can be configured to not HTML-encode the text that you bind to it from a strongly typed list of strings!).

History

  • 1.0 (Original, 14 July 2008): Original version.
  • 1.1 (15 July 2008): Fixed a null-reference when the control rendered, if no items were in the list.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

bgs264
Software Developer (Senior)
United Kingdom United Kingdom
I graduated with a First class honours degree in Computer Science from the University of Salford in June 2006. Shortly after I graduated, I started my first job as a web developer in a small consultancy company in the North-West. I have since moved to a larger organisation in Manchester, which is a bit closer to my home.
 
My development is 99% ASP.NET based with the remaining 1% being ad-hoc console applications or Windows services, and although I prefer to develop in C# (just because I think it is cleaner), VB is what is used in the team.

Comments and Discussions

 
GeneralThree lines of code.. hope this helps someone.. Pinmembermonkeyboy6823-Jul-09 20:50 
Generalnever underestimate the power of a google... [modified] PinmemberRobinson-View28-Oct-08 11:46 
GeneralRe: never underestimate the power of a google... Pinmemberbgs26430-Oct-08 2:00 
GeneralAnother custom version (still inherits from System.Web.UI.WebControls.BulletedList though) PinmemberCarl Reid21-Jul-08 2:37 
GeneralRe: Another custom version (still inherits from System.Web.UI.WebControls.BulletedList though) Pinmemberbgs26421-Jul-08 2:47 
GeneralRe: Another custom version (still inherits from System.Web.UI.WebControls.BulletedList though) PinmemberCarl Reid21-Jul-08 2:50 
GeneralRe: Another custom version (still inherits from System.Web.UI.WebControls.BulletedList though) Pinmemberbgs26421-Jul-08 3:00 
GeneralI wrote something like this myself PinmemberSpeednet_12-Jul-08 7:33 
GeneralRe: I wrote something like this myself PinmemberNeetflash31-Jul-09 16:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.141022.2 | Last Updated 17 Jul 2008
Article Copyright 2008 by bgs264
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid