Clear Your Calendar

Clean Up the Clutter with a Custom DropDownCalendar Control





Clear Your Calendar

Clean Up the Clutter with a Custom DropDownCalendar Control


By Steve C. Orr


The Calendar control included with ASP.NET provides an easy and intuitive way for users to visually select dates. However, it takes up so much screen real estate that you may not be able to fit many other controls on the page. The custom DropDownCalendar control detailed in this article solves the problem with a small footprint that expands only when needed.


The custom DropDownCalendar control described in this article inherits from the standard ASP.NET Calendar control and extends it with the ability to show and hide on demand. The control also provides useful new smart tags that make configuration easy. While touring the source code (available for download; see end of article for details), you can learn how to add smart tags to your own controls for a truly professional polish.


To use this control, download the sample code and add the included DropDownCalendar.dll to your Visual Studio 2005 toolbox. Then drag it onto any WebForm to get started using it. At first it will appear much like a standard DropDownList control. If you wish to drop down the calendar at design time, simply set the control s Expanded property to True. If you leave this property set to True, the control will appear expanded by default when the page is loaded in the browser at run time. Other useful properties are shown in Figure 1.


Unique DropDownCalendar Properties



Sets or gets the initial dropdown state. Default: False


Specifies whether the selected date should be displayed in the text area with a long or short date format. Default: True


The style applied to the text area.


Sets or gets the color of the background of the button. Default: White


Sets or gets the color of the button arrow. Default: Black

Figure 1: The DropDownCalendar control provides several new and useful properties beyond those the base Calendar control already provides.


The ASPX declaration looks roughly like this (depending on how the control properties have been configured):





At run time the control looks a lot like a dropdown list with an expandable calendar bolted onto the bottom, as shown in Figure 2. In design reality, the control is actually inherited directly from the Calendar control and the dropdown functionality is bolted onto the top.


Figure 2: The DropDownCalendar control s calendar can hide and show on demand, much like the list portion of a DropDownList control.


Much like a standard DropDownList control, the calendar portion of this control can be shown and hidden on demand without requiring a postback. When the user clicks on a date, the form posts back and raises the SelectionChanged event (just like the standard Calendar control) and then the dropdown portion will be automatically hidden. Of course, the user can always expand the calendar again and pick a different date if you choose to let them.


Inside Out

Alright, it s time to turn this control inside out and take a look at the code that makes it work. The basic structure of the control is outlined in Figure 3. This structure is fairly standard for any custom Web control. The Designer attribute is there to support the new smart tag functionality, which will be explained in more detail later.


"), _


Public Class DropDownCalendar

 Inherits Calendar


    'Public Properties...

     'Overriden Subroutines...

End Class

Figure 3: The DropDownCalendar control inherits directly from the Calendar control, declares a designer for smart tag support, extends the control with some custom properties, and overrides a few base subroutines.


The DropDownCalendar control overrides three subroutines of the base Calendar control. The most significant of these is the Render subroutine, which is where nearly all the real work happens to create the DropDownCalendar control (see Figure 4).


Protected Overrides Sub Render(ByVal _

 writer As HtmlTextWriter)

 'display calendar on top of other elements

 MyBase.Style(HtmlTextWriterStyle.Position) = "absolute"

 'hide or show the calendar initially

 If Me.Expanded Then

     Me.Style(HtmlTextWriterStyle.Display) = "block"


     Me.Style(HtmlTextWriterStyle.Display) = "none"

 End If

 'create the containing table

 Dim tbl As New Table

 tbl.Enabled = Me.Enabled

 tbl.BorderWidth = New Unit(1, UnitType.Pixel)

 tbl.BorderColor = Drawing.Color.Black

 tbl.CellSpacing = 1

 tbl.Width = Me.Width

 tbl.ID = Me.ClientID & "_tbl"

 If Me.Enabled Then

     tbl.Style(HtmlTextWriterStyle.Cursor) = "hand"

     tbl.Attributes.Add("Onclick", OnClickJS() )

 End If

 'create the text area

 Dim tr As New TableRow


 Dim td As New TableCell


 td.Width = New Unit(100, UnitType.Percentage)


 Dim dt As String = IIf(Me.DisplayLongDate, _

     Me.SelectedDate.ToLongDateString, _


 td.Controls.Add(New LiteralControl(dt))

 'create the (simulated) button

 Dim td2 As TableCell = New TableCell


 td2.BorderStyle = WebControls.BorderStyle.Outset

 td2.BorderWidth = 2

 td2.BackColor = Me.ButtonBackColor

 td2.ForeColor = Me.ButtonForeColor

 td2.Font.Name = "Webdings"

 td2.Controls.Add(New LiteralControl("6"))

 'render the containing table


 'render the base calendar control

 If Me.DesignMode = False OrElse Me.Expanded Then


 End If

End Sub

Figure 4: The Render event draws the text area and the button that drops down the calendar. The rendering of the calendar is delegated to the base Calendar control.


The first line is important. By ensuring the calendar is rendered with absolute positioning, this will allow the calendar to hover over any controls that are placed just below the DropDownCalendar control when expanded, just like the list portion of a DropDownList control.


The second code block specifies the Display style of the calendar, which specifies whether it should initially be visible (block) or invisible (none). When the arrow button or text area is clicked by the user at run time, this value will be toggled by client-side code to hide and show the calendar on demand. This JavaScript is output at the end of the third code block, and is assigned to the client-side OnClick event.


The fourth code block shown in Figure 4 continues creating the HTML table that positions everything, and creates the text area that will display the selected date in the configured long or short string format. The fifth code block styles one of the cells to look like a button so the user will understand this is a clickable area.


To wrap things up, the containing HTML table is rendered, which renders all the other controls that have been instantiated so far. Finally, the base Calendar control is then commanded to render itself.


To polish things nicely, the OnVisibleMonthChanged event is overridden to keep the calendar portion expanded between postbacks when the user changes months:


Protected Overrides Sub OnVisibleMonthChanged(ByVal _

   newDate As Date, ByVal previousDate As Date)

   'keep calendar expanded after month change

   Me.Expanded = True

   MyBase.OnVisibleMonthChanged(newDate, previousDate)

End Sub


Similarly, the OnSelectedChanged event is overridden to ensure the calendar portion automatically hides once the user has selected a date:


Protected Overrides Sub OnSelectionChanged()

   'hide calendar by default after selection

   Me.Expanded = False


End Sub


When overriding base control events, it s always good practice to call the base method to ensure the underlying control performs normally its portion of the functionality.


Smart Tags

Three things must be done to enhance a custom control with smart tags. First, the control class needs a Designer attribute that refers to a custom Designer class. This is demonstrated in Figure 3. Second, the custom Designer class must add a DesignerActionList (full of smart tag actions) to its DesignerActionListCollection, as shown in Figure 5. Finally, the DesignerActionList class (shown in Listing One) must programmatically add each desired DesignerAction. For all this to work, the control s project must have a reference to System.Design.dll.


Public Class DropdownCalendarDesigner

 Inherits Web.UI.Design.WebControls.CalendarDesigner

 Private o_ActionLists As DesignerActionListCollection

 Public Overrides ReadOnly Property ActionLists() As _



     If o_ActionLists Is Nothing Then

       o_ActionLists = New DesignerActionListCollection

       Dim ctl As DropDownCalendar = _

         CType(Component, DropDownCalendar)

       o_ActionLists.Add(New DropdownCalendarActions(ctl))

     End If

     Return o_ActionLists

   End Get

 End Property

End Class

Figure 5: The Designer for the DropDownCalendar control inherits and extends the CalendarDesigner, extending it with smart tag actions that are defined in the custom DropDownCalendarActions class.


There s not much code to the Designer class in Figure 5 because it is only implementing smart tag support. However, Designer classes can also unlock other advanced design-time features, as well, such as support for control templates and auto-formatting. The code in Figure 5 essentially does little more than add a reference to the DropDownCalendarActions class, which is shown in Listing One.


The primary function shown in Listing One, GetSortedActionItems, creates each item that will be shown in the smart tags dialog box, which is illustrated in Figure 6. A new DesignerActionItemCollection object is instantiated and filled with smart tags, otherwise known as DesignerActionItems. There are four kinds of DesignerActionItems: Headers, Properties, Methods, and Text. All but the latter are demonstrated in Listing One.


Figure 6: The smart tags for the DropDownCalendar control were added programmatically via a Designer class and a DesignerActionList class. Notice that the method item smart tags also show up automatically at the bottom of the Properties window.


Headers are shown in bold text, properties are displayed as editable fields, and commands tend to show up as hyperlinks that execute custom methods on demand. Properties or more specifically, DesignActionPropertyItems are quite versatile in their display; for example, automatically showing up as textboxes when representing strings, dropdownlists when representing enumerations, or checkboxes when representing Boolean values.


Notice that the properties and methods all have the header name passed as a constructor parameter so Visual Studio knows how to group them. Also notice the first parameter for each property item refers to a property declaration further down in Listing One, which does the work of setting and getting the property value from the underlying DropDownCalendar control. Similarly, the first constructor parameter for each method item refers to a function listed further down in Listing One. These methods do the real work. Although the examples here are simple, they could be as complex as necessary launching Windows forms, fancy wizards, or whatever else you can imagine.



Smart tags are a modern design-time feature that can enhance any control with a professional polish. They are a user-friendly way to allow application developers to configure controls in quick, intuitive ways. There is a significant amount of code involved, but most of it is simple and boilerplate.


Nearly any large control can be similarly enhanced with dropdown functionality so it can hide away when not immediately needed. You could try inheriting from a GridView control instead of a Calendar control, for example, which is a common way to create multi-column DropDownLists. Similarly, I ve seen people place a TreeView control into a dropdown area to decrease the footprint of that otherwise bulky control. I can also imagine a dropdown CheckBoxList or RadioButtonList. How about a dropdown Login control, or maybe even a dropdown Crystal Report? I encourage you to combine your imagination and your skills with the information you ve learned here to come up with a custom control that saves your company time and money.


The complete source code for the DropDownCalendar control is available for download (in both VB and C#).


Steve C. Orr is an MCSD and a Microsoft MVP in ASP.NET. He s been developing software solutions for leading companies in the Seattle area for more than a decade. When he s not busy designing software systems or writing about them, he can often be found loitering at local user groups and habitually lurking in the ASP.NET newsgroup. Find out more about him at or e-mail him at mailto:[email protected].


Begin Listing One the DesignerActionList class

Public Class DropdownCalendarActions

 Inherits System.ComponentModel.Design.DesignerActionList

 Private ctl As DropdownCalendar

 Public Overrides Function GetSortedActionItems() As _


 Dim o_Items As _

   DesignerActionItemCollection = _

   New DesignerActionItemCollection

   ' create headers

   o_Items.Add(New _


   Dim Header2 As String = "Developed by Steve C. Orr"

   o_Items.Add(New _


   'add property items

   o_Items.Add(New _

     DesignerActionPropertyItem("DayNameFormat", _

     "Day Name Format", "Properties"))

   o_Items.Add(New _

     DesignerActionPropertyItem("SelectedDate", _

     "Selected Date", "Properties"))

   o_Items.Add(New _

     DesignerActionPropertyItem("DisplayLongDate", _

     "Display Long Date Format", "Properties"))

   'add method items

   o_Items.Add(New _

   DesignerActionMethodItem(Me, "SelectJan1", _

     "Select January 1st", "Properties", _

     "Selects January First", True))

   o_Items.Add(New _

     DesignerActionMethodItem(Me, "ToggleExpanded", _

     "Toggle Expanded property", "Properties", _

     "Toggles the dropdown state", True))

   o_Items.Add(New _

     DesignerActionMethodItem(Me, "LaunchWebSite", _

     "", Header2, _

     "Launches Steve Orr's web site.", True))

    Return o_Items

 End Function

#Region " Properties "

 Public Property DayNameFormat() _

  As System.Web.UI.WebControls.DayNameFormat


   Return ctl.DayNameFormat

 End Get

 Set(ByVal value As DayNameFormat)

   GetProperty("DayNameFormat").SetValue(ctl, value)

 End Set

 End Property

 Public Property SelectedDate() As Date


    Return ctl.SelectedDate

  End Get

  Set(ByVal value As Date)

    GetProperty("SelectedDate").SetValue(ctl, value)

  End Set

 End Property

 Public Property DisplayLongDate() As Boolean


    Return ctl.DisplayLongDate

  End Get

  Set(ByVal value As Boolean)

    GetProperty("DisplayLongDate").SetValue(ctl, value)

  End Set

 End Property

#End Region

#Region " Methods "

 Public Sub New(ByVal ctlCal As DropDownCalendar)


   ctl = ctlCal

 End Sub

 Public Sub LaunchWebSite()

   Dim sURL As String = ""




   End Try

 End Sub

 Public Sub ToggleExpanded()

   GetProperty("Expanded").SetValue(ctl, Not ctl.Expanded)

 End Sub

 Public Sub SelectJan1()

   GetProperty("SelectedDate").SetValue(ctl, _

     Date.Parse("Jan 1 " & Date.Now.Year.ToString))

 End Sub

 Private Function GetProperty(ByVal _

   propertyName As String) As PropertyDescriptor

   Dim o_Property As PropertyDescriptor = _


   If o_Property IsNot Nothing Then

     Return o_Property


     Throw New _

       ArgumentException("Invalid property", _


   End If

 End Function

#End Region

End Class

End Listing One




Hide comments


  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.