65.9K
CodeProject 正在变化。 阅读更多。
Home

创建 BulletedList 控件以替换 asp:BulletedList

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.67/5 (8投票s)

2008 年 7 月 11 日

CPOL

4分钟阅读

viewsIcon

47844

downloadIcon

169

我需要一个简单的控件来显示基于强类型字符串列表的列表。

引言

我想在网页上显示一个项目列表(在 <ul> 标签内渲染的 <li> 标签),该列表基于我从某个数据源收集的强类型字符串对象列表。

我注意到 .NET 中有一个 BulletedList 控件,所以我尝试了一下。我将 DataSource 设置为我的 List(Of String) 并调用了 DataBind()

它奏效了——勉强奏效。项目符号列表显示了我列表中的每个字符串的内容,但它坚持对每个项目进行 HTML 编码。由于列表中有超链接(<a href="somepage.htm">click me</a>),它被渲染到输出流中为 &lt;a href="somepage.htm"&gt;click me&lt;/a&gt;,导致我在页面上没有获得超链接。真令人沮丧。感谢微软的自动编码!

背景

我花了一些时间研究 BulletedList 控件并搜索这个问题,但它似乎只是 BulletedList 的一个“特性”,并且无法控制(我可能是错的!)。我没有使用 asp:BulletedList,而是编写了一个 Repeater 来渲染这些项目,但在 .aspx 页面中看起来很混乱,而且我对此并不满意——我想要一个控件,因为我希望在几个地方使用它——一个 Repeater 可能只适用于一个实例,但不是多个。

我放弃了框架的另一个短视的“特性”,出去享用了一个肉丸三明治和燕麦葡萄干饼干,还有一杯健怡可乐。

在三明治店里,一边看着七月的雨水拍打着外面的路面,我决定自己写一个控件来做我想做的事情——我认为我的需求非常基本,而且我认为我花费在搜索解决方案上的时间,本可以自己解决它。现在,我只需要回到马路对面回到办公室,穿着短袖衬衫,在大雨中。我爱曼彻斯特。

开发代码

我的第一步是创建一个 .vb 类文件,我将其命名为 BulletedList.vb。我将该类放在一个命名空间中,以便以后方便注册它,并使其继承自 Control

接下来,我创建了一个名为“Items”的属性,该属性提供对我想渲染的项目列表的读/写访问。请记住,我想使用强类型的字符串列表。我将项目保存在控件的 ViewState 中。

        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

因此,我现在可以保存要在页面上显示的字符串列表。接下来是告诉控件它应该如何渲染它们。我只是覆盖了控件的“Render”方法,并提供了一些自定义逻辑。

        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

如您所见,这相当直接。如果列表中有任何项目,我将创建开头的 <ul> 标签,然后将每个包含在 <li> 标签中的项目写出来。一旦所有项目都已写出,我将关闭 <ul> 标签,并调用基类的 Render 方法(它实际上并没有做什么,只是为了完整性)。

HTML 编码文本

我理解从安全角度考虑 HTML 编码文本的意图;从数据存储中检索的 HTML 数据(尤其是在数据来自未知来源时)在显示到网页之前应始终进行 HTML 编码,以帮助防止注入攻击。

出于这个原因,我提供了另一个属性 EncodeHtml,允许控件的用户决定是否要在输出渲染之前对其进行编码。该属性是一个简单的布尔值,保存在 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

然后,我对 Render 方法进行了修改,以考虑此属性,并在需要时对文本进行 HTML 编码。这标志着控件实现的结束。

        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

使用代码很简单。首先,在 .aspx 文件的顶部注册控件。

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

接下来,在 .aspx 标记中添加控件,您希望项目符号列表出现的位置。

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

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

最后,在 Page_Load 或类似方法中,将控件绑定到您所需的字符串列表。

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

就是这样。“应该可以正常工作”。

可下载的文件包含一个完整的 XML 注释代码列表供您查阅。欢迎提出任何意见(特别是,如果您能告诉我 asp:BulletedList 是否可以配置为 **不** HTML 编码您从强类型字符串列表中绑定到它的文本!)。

历史

  • 1.0(原始,2008 年 7 月 14 日):原始版本。
  • 1.1(2008 年 7 月 15 日):修复了控件渲染时列表为空的 null 引用问题。
© . All rights reserved.