LANGUAGES: VB.NET | C#
ASP.NET VERSIONS: 2.x
Hot Menu Options
Make Your Sites Sizzle with a Custom HoverList Control
You can never have too many menu controls. Ever. But more is not always good enough
— they have to be unique, as well. A unique menu control can really differentiate
a Web site, making it stand out from the information overload that is the World
Wide Web. To help you get moving in this distinctive direction, try using the HoverList
custom control provided with this article to spice up your site.
The HoverList control (based on the menu at the top of the home page of this site) contains
configurable menu items that highlight as the mouse is moved over them at run time.
The list can be specified at design time or run time, and may optionally be data
bound. Each list item consists of a string value and a formatted text item that
may optionally include HTML. A configurable header area is also optionally included
(see Figure 1).

Figure 1: The HoverList control contains
a configurable list of menu items that can be highlighted with various color effects
as the mouse hovers over them.
To use this control, download the sample code and add the included HoverList.dll
to your Visual Studio 2005 toolbox (see end of article for download details). Then
drag it onto any WebForm to get started using it. The ASPX declaration looks roughly
like this (depending on how the control’s properties have been configured):
<cc1:hoverlist id="HoverList1"
runat="server"
borderstyle="Solid"
borderwidth="1px"
datasourceid="SiteMapDataSource1"
datatextfield="Title"
datavaluefield="Url"
hoverbackcolor="Blue" hoverforecolor="LightCyan"
padding="0.2em"
width="200px">
</cc1:hoverlist>
The design-time experience is very much like working with a ListBox because the
ListBox and the HoverList control both inherit from ListControl (as explained in
more detail later). The HoverList’s most noteworthy members are listed in the table
in Figure 2. There are several properties for configuring the appearance
of the header area of the control, and a couple important properties for configuring
the color changes that happen when the mouse is hovered over each menu item.
|
Noteworthy HoverList Members
|
Description
|
|
OnSelectedIndexChanged event
|
This event is raised whenever the user clicks on one of the menu items
|
|
ShowHeader property
|
Specifies the visibility of the header area.
Default: True
|
|
HeaderText property
|
Specifies the text that is displayed in the header area.
|
|
HeaderBackColor property
|
Specifies the background color of the header area.
Default: LightBlue
|
|
HeaderForeColor property
|
Specifies the color of the header text.
Default: Black
|
|
HeaderFont property
|
Specifies the font of the header text.
|
|
HoverBackColor property
|
Specifies the background color of the menu when the mouse hovers over it.
Default: Blue
|
|
HoverForeColor property
|
Specifies the text color of the menu item when the mouse hovers over it.
Default: LightCyan
|
|
Padding property
|
Specifies the padding around the edge of the control.
Default: 0.2em
|
|
HorizontalAlign property
|
Specifies the alignment of the menu items.
Default: Center
|
|
AppendDataBoundItems property
|
Appends data bound items to statically declared list items.
Default: False
|
Figure 2: The HoverList control provides
several useful members in addition to those that the base ListControl already provides.
The HoverList control’s menu items can be configured at design time via the standard
ListItem Collection Editor shown in Figure 3. Alternatively, items can be added
programmatically at run time or standard data-binding techniques can be applied.
You can even combine these techniques, thanks to the AppendDataBoundItems property.
Figure 3: The HoverList control supports
standard data-binding techniques, or items can be added at design time through the
ListItem Collection Editor dialog box.
AppendDataBoundItems is a new property of the base ListControl class (as of ASP.NET
version 2.0). It lets you declare one or more list items at design time, and then
also add data-bound list items at run time. This is especially useful for controls
such as DropDownList, because you can configure the first item to say “Choose an
item from the list” and then add the rest of the list via standard data binding.
This was not possible in ASP.NET 1; instead, you either needed to ditch data binding
or add a dummy record to the data source to achieve such functionality.
When the user clicks on one of the HoverList’s menu items at run time, the page
posts back and the OnSelectedIndexChanged event is raised, as demonstrated here:
Protected
Sub HoverList1_SelectedIndexChanged(ByVal
_
sender As
Object, ByVal
e As System.EventArgs) _
Handles
HoverList1.SelectedIndexChanged
Response.Write("You
Clicked: " & HoverList1.SelectedValue)
End
Sub
That covers most of what you need to know to use the HoverList control. If you’re
the intellectually curious type (which I assume most of you are), keep reading to
tour the source code and find out about the details of its inner workings.
Viscera
One of the most fundamental pieces of information about the HoverList control is
that it inherits from ListControl. ListControl is an abstract base class provided
by the .NET Framework from which many common controls inherit. A few of the standard
ASP.NET controls that extend the ListControl class are ListBox, DropDownList, and
CheckBoxList. Like these controls, HoverList doesn’t need to deal with trivia, such
as data binding, because that is all handled by the base ListControl class. This
greatly simplifies the code, reducing it to little more than an exercise in HTML
rendering. Essentially, the HoverList control consumes the collection of ListItems
that is managed by the ListControl class, and renders custom HTML from that data.
The general structure of the control is shown here:
<DefaultProperty("HeaderText"), _
ToolboxData("<{0}:HovrList runat=server></{0}:HovrList>")>
_
Public
Class HoverList
Inherits
ListControl
Implements
IPostBackEventHandler
'TODO: constructor
'TODO: public properties
'TODO: Rendering
'TODO: Postback handling
End
Class
Another important detail is that the control implements the IPostBackHandler interface.
This enables the control to handle postbacks in a standard way. The associated code
is located in the RaisePostBackEvent routine. The logic is simple for the HoverList
control: Unselect any previously selected item and ensure that the item the user
clicked is now the selected item. Then hand off control to the base class — which
will raise the standard OnSelectedIndexChanged event to the page:
Public
Sub RaisePostBackEvent(ByVal
_
eventArgument As String)
Implements _
System.Web.UI.IPostBackEventHandler.RaisePostBackEvent
If
SelectedItem IsNot Nothing
Then
SelectedItem.Selected
= False
End
If
Dim
li As ListItem = _
Items.FindByValue(eventArgument)
If
li IsNot Nothing
Then li.Selected = True
MyBase.OnSelectedIndexChanged(Nothing)
End
Sub
You’ll notice references to the SelectedItem property and the Items collection,
but you’ll find no such properties in the HoverList source code. Rather, these properties
are inherently available from the base ListControl class. Therefore, the HoverList
control only needs to define the unique properties it requires for its customizable
rendering chores. While most of the properties are utilitarian in nature, a couple
of them are shown in Figure 4 to give you a taste.
<Bindable(True), Category("Appearance"),
_
Description("Sets or gets the font color of the header.")> _
Public
Property HeaderForeColor()
As System.Drawing.Color
Get
If
ViewState("HeaderForeColor")
IsNot Nothing Then
Return
CType(ViewState("HeaderForeColor"),
Color)
Else
Return
Color.Black 'default
End
If
End Get
Set(ByVal value As Color)
ViewState("HeaderForeColor")
= value
End Set
End
Property
Private
Const Content As
_
System.ComponentModel.DesignerSerializationVisibility
= _
DesignerSerializationVisibility.Content
Private
_lblHeader As Label = New
Label
<Bindable(True), Category("Appearance"),
_
Description("The font applied to the header area."), _
NotifyParentProperty(True), _
DesignerSerializationVisibility(Content)>
_
Public
Property HeaderFont() As
FontInfo
Get
If ViewState("HeaderFont")
IsNot Nothing
Then
Return
CType(ViewState("HeaderFont"),
FontInfo)
Else
Return _lblHeader.Font
End If
End Get
Set(ByVal value
As FontInfo)
ViewState("HeaderFont") = value
End Set
End
Property
Figure 4: Because the concept of
a header is foreign to the base ListControl class, the HoverList control must explicitly
define header-related properties.
The HeaderForeColor property is needed so the application developer may specify
which color they would like the text of the header area to be. The property stores
the property in ViewState, and uses Black by default. The HeaderFont property is
a little more complicated because of the fact that the Font property is complex
and contains many sub-properties. Most of the details related to this are managed
by .NET automatically — if you tell it to. That’s what the extra attributes are
for — NotifyParentProperty and DesignerSerializationVisibility are critical for
ensuring the properties are persisted properly, especially at design time.
Of course, all these properties are pointless until they are used by the rendering
code to output the customized HTML that makes up the HoverList control. The overridden
Render event is listed in Figure 5.
Figure 5: The overridden Render event delegates rendering tasks to several other internal functions.
As you can see, each piece of the control is rendered by custom functions: CreateContainer,
CreateHeader, and CreateItem. The CreateContainer function listed in Figure
6 is a fairly simple function that does little more than instantiate
a Panel control and set its properties to some proper defaults. This panel will
act as the container for the other elements of the HoverList control. Many of the
HoverList’s properties are piped through to be managed by the Panel control.
Figure 6: The CreateContainer function instantiates a Panel control to contain the child controls that make up the HoverList control.
If the application developer has set the ShowHeader property of the HoverList control
to True, then the CreateHeader function is called to generate the header area of
the control. As demonstrated here, the header area is nothing more than a Label
control:
Private
Sub CreateHeader(ByVal
pnl As Panel)
Dim
lbl As Label = _lblHeader
lbl.Text =
Me.HeaderText & "<br />"
'For Firefox
lbl.Width =
New Unit(100, UnitType.Percentage)
lbl.BackColor =
Me.HeaderBackColor
lbl.Font.CopyFrom(Me.HeaderFont)
lbl.ForeColor =
Me.HeaderForeColor
pnl.Controls.Add(lbl)
End
Sub
The For loop shown in Figure 5 loops through each ListItem managed by the base ListControl
class and renders each item individually by invoking the CreateItem subroutine shown
in Figure 7. This is what makes up the bulk of the control’s final
rendered appearance.
Private
Sub CreateItem(ByVal
pnl As Panel, _
ByVal li
As ListItem)
Dim lbl
As New Label
lbl.Text = li.Text &
"<br />" 'For Firefox
lbl.Width = New
Unit(100, UnitType.Percentage)
lbl.BackColor = Me.BackColor
lbl.ForeColor = Me.ForeColor
If li.Enabled
Then
lbl.Style(HtmlTextWriterStyle.Cursor) = "hand"
lbl.Attributes("onMouseOver") = _
"this.style.backgroundColor='" & _
ColorTranslator.ToHtml(Me.HoverBackColor) _
&
"';" & "this.style.color='"
& _
ColorTranslator.ToHtml(Me.HoverForeColor) _
& "';"
lbl.Attributes("onMouseOut") = _
"this.style.backgroundColor='"
& _
ColorTranslator.ToHtml(Me.BackColor)
_
& "';" &
"this.style.color='" & _
ColorTranslator.ToHtml(Me.ForeColor)
& "';"
lbl.Attributes("onClick") = _
Page.ClientScript.GetPostBackClientHyperlink(Me,
_
li.Value)
End If
lbl.Font.CopyFrom(Me.Font)
pnl.Controls.Add(lbl)
End
Sub
Figure 7: The CreateItem subroutine is invoked once for every ListItem that’s managed by the underlying ListControl class. It instantiates and configures a Label control to represent each ListItem.
Like the header area, each ListItem will be represented by a Label control. The
CreateItem subroutine instantiates and configures a Label control to represent the
ListItem parameter. Because the ASP.NET 2.0 version of the standard ListIem class
now includes an Enabled property, it is used here to represent a richer rendering
for enabled items. For example, the Label’s Cursor style is set to “hand” so that
the mouse cursor will appear as a hand icon when moved over enabled items at run
time (as shown in Figure 1).
The CreateItem subroutine shown in Figure 7 continues by adding client-side onMouseOver
and onMouseOut events to the Label control to implement the unique color changes
that occur when the mouse moves over the item at run time. These client-side events
use JavaScript to change the text color and the background color of the label as
the mouse enters and leaves its boundaries.
The final client-side event to be wired up is the onClick event. When the user clicks
on the label, the page will post back and, ultimately, the OnSelectedItemChanged
event will fire, allowing the page to respond to the user’s command. ASP.NET’s GetPostBackClientHyperlink
method dynamically generates the code that invokes the post back. This method uses
ASP.NET’s adaptive rendering engine to generate proper PostBack code, no matter
which browser or device is being utilized by the end user.
Finally, the selected font is applied to the label, and the label is added to the
containing panel’s control collection. Then the panel’s complete control tree is
finally output when execution returns to the last line of the render function of
Figure 5.
Conclusion
The HoverList is a nice control to have around to add a quick and functional menu
of options to the user. Its visual interactivity adds a bit of spice to a Web site
without being overly flashy. The design-time experience is quite similar to that
of a ListBox, so the learning curve should be small.
By inheriting from ListControl, rich functionality can be taken advantage of with
little or no code necessary — such as data binding and practical design-time features.
Sprinkle in a touch of rendering code with a dash of client-side JavaScript code
and a useful little control starts to emerge. Using the techniques demonstrated
in this article, you can extend the HoverList control with enhanced functionality,
or use the knowledge to create a custom control that lives up to your own dreams
— or at least your manager’s requirements.
The sample code in this article is available for download.
This article was originally published in ASP.NET Pro Magazine.