Click here to Skip to main content
13,049,172 members (72,832 online)
Click here to Skip to main content
Add your own
alternative version


396 bookmarked
Posted 2 Nov 2003


, 19 Feb 2004
Rate this:
Please Sign up or sign in to vote.
A data-driven, templated sub-class of the ASP.NET Calendar control


This article presents a sub-class of the ASP.NET Calendar control, to function as a data-driven display calendar with template support for item layout. Though there are limitations to the approach of sub-classing Calendar, it is a useful alternative to creating such a control from scratch, as significant functionality can be inherited. The DataCalendar class is described with specific attention to data binding, templates, and styles.


The ASP.NET Calendar control offers the ability to navigate a monthly calendar and select dates. But the standard Calendar control lacks support for data binding, so extra steps are required to display items from a database. The standard control does support a DayRender event, which provides a means to customize the display of individual days. I was interested in a control that functions more closely like a Repeater or DataList, with the ability to bind to a data source and use templates to control item display. Sub-classing the Calendar control seemed a good place to start.

To support data binding, a custom control will typically expose a DataSource property, override the Control.DataBind method, and construct a control hierarchy within CreateChildControls. This also usually involves maintaining ViewState for each of the child controls so explicit binding does not have to occur with each page postback. The Microsoft .NET SDK documentation offers source examples describing how to develop a data-bound control. The book Developing Microsoft ASP.NET Server Controls and Components by Nikhil Kothari and Vandana Datye (Microsoft Press, 2003) is also recommended for a full description of developing data-bound controls.

There are problems using the existing Calendar control this way. When a Repeater is bound to a data source, all items of that source are enumerated to generate child controls. With a Calendar, the display layout is dependent on a fixed set of days. Creating child controls for each item with ViewState maintained, particularly for those items that don't fall within the displayed month, doesn't seem practical. As it is, the Calendar control already creates TableRows and TableCells for child controls; if that were to be overridden, the month-based layout would be lost. If we can't take advantage of the layout functionality provided by the Calendar control, there isn't much point to inheriting from it.

Seeing these kinds of issues makes clear why the DayRender event is offered in the first place. DayRender is fired once for each day displayed during the Render event of the Calendar control. It becomes possible to simulate a data-bound control by exposing a DataSource property, then enumerating that data listing in an overridden version of the Calendar.OnDayRender method.

This approach has some important ramifications. The Render event comes relatively late in the control's lifecycle, and isn't usually where child controls are created. Child controls added at this stage will not fire events. We can't, for example, add a Button control in each day cell and code for its Click event - the Click event will not fire. On the other hand, content for display such as literal HTML or Label controls may be added without penalty. If we can tolerate a lack of event-firing controls rendered in day cells, the approach of sub-classing the Calendar control offers some terrific benefits: built-in styling capabilities, month-to-month navigation, day/week/month selection, a useful layout - all in all, there are enough benefits to this approach to make it worthwhile.

The DataCalendar Class

The DataCalendar class inherits from Calendar and implements INamingContainer. The constructor sets some defaults that make sense for a calendar whose primary purpose is to display entries as static content.

public class DataCalendar : Calendar, INamingContainer
    // Constructor
    public DataCalendar() : base()
        // since this control will be used for displaying
        // events, set these properties as a default
        this.SelectionMode = CalendarSelectionMode.None;
        this.ShowGridLines = true;

Simulating Data Binding

The essential properties for making this a data-driven control are defined as DataSource, DataMember, and DayField. DataSource is implemented here as either a DataSet or DataTable object, representing the listing of calendar items. If a DataSet object is supplied, then the DataMember property is implemented to allow the user to specify which table in the set to use. DayField is the name of the column in DataSource that represents the event date.

private object _dataSource;
private string _dataMember;
private string _dayField;

// Support either a DataSet or DataTable object
// for the DataSource property
public object DataSource {
    get {return _dataSource;}
        if (value is DataTable || value is DataSet)
            _dataSource = value;
            throw new Exception("The DataSource property " +
              "of the DataCalendar control must be a " +
              "DataTable or DataSet object");

// If a DataSet is supplied for DataSource,
// use this property to determine which
// DataTable within the DataSet should
// be used; if DataMember is not supplied,
// the first table in the DataSet will
// be used.
public string DataMember {
    get {return _dataMember;}
    set {_dataMember = value;}

// Specify the name of the field within
// the source DataTable that contains
// a DateTime value for displaying in the
// calendar.
public string DayField {
    get {return _dayField;}
    set {_dayField = value;}

Often a data-bound control will support several types of objects for its DataSource property, such as those objects that implement the IEnumerable interface. For simplicity I chose to stay with a DataTable (or a table within a DataSet). The need for a DayField property to specify a date element within the data source also lends well to using a DataTable as opposed to other types of IEnumerable lists.

We'll use the Render method to inspect the DataSource property at run-time, determining if a DataSet or DataTable has been specified. We can then set up the private variable _dtSource to point to the appropriate DataTable object, and allow the base class Render method to execute.

private DataTable _dtSource;

protected override void Render(HtmlTextWriter html)
    _dtSource = null;

    if (this.DataSource != null && this.DayField != null)
        // determine if the datasource is a DataSet or DataTable
        if (this.DataSource is DataTable)
            _dtSource = (DataTable) this.DataSource;
        if (this.DataSource is DataSet)
            DataSet ds = (DataSet) this.DataSource;
            if (this.DataMember == null || this.DataMember == "")
                // if data member isn't supplied,
                // default to the first table
                _dtSource = ds.Tables[0];
                // if data member is supplied, use it
                _dtSource = ds.Tables[this.DataMember];
        // throw an exception if there is a problem
        // with the data source
        if (_dtSource == null)
            throw new Exception(
                "Error finding the DataSource.  Please check " +
                " the DataSource and DataMember properties.");
    // call the base Calendar's Render method, allowing
    // OnDayRender to be executed.

As DataCalendar inherits from Calendar, we override the OnDayRender method to customize the display of individual days. The argument cell represents the TableCell being rendered and acts as a placeholder for additional content. The specific date in question is derived from the CalendarDay argument day. We'll use the _dtSource private variable previously set by Render. With this we'll create a DataView object to filter the DataTable, extracting only those items that match the day argument based on the value of the DayField column. The code forces a "MM/dd/yyyy" date format when constructing the RowFilter as required for date comparisons in such expressions. The filter is also constructed to take into account the possibility of time values within the DayField column.

protected override void OnDayRender(TableCell cell, CalendarDay day)
    // _dtSource was already set by the Render method
    if (_dtSource != null)
        // We have the data source as a DataTable now;
        // filter the records in the DataTable for the given day;
        // force the date format to be MM/dd/yyyy
        // to ensure compatibility with RowFilter
        // date expression syntax (#date#).
        // Also, take the possibility of time
        // values into account by specifying
        // a date range, to include the full day
        DataView dv = new DataView(dtSource);
        dv.RowFilter = string.Format(
           "{0} >= #{1}# and {0} < #{2}#",

        // are there events on this day?
        if (dv.Count > 0) {
            // there are events on this day;
            // no events this day;


    // call the base render method too
    base.OnDayRender(cell, day);


Supporting Templates

Another goal of the DataCalendar is to make use of templates. Templates allow for content layout to be defined within the HTML portion of an .aspx page by a page designer, rather than hard-coded into the class by a developer. A template contains HTML elements and ASP.NET controls, within which data binding expressions may be applied and resolved. The Repeater control for example supports, among others, a HeaderTemplate, ItemTemplate, and FooterTemplate. The DataCalendar control will support an ItemTemplate that works in the .aspx page like this:
<dc:DataCalendar id="cal1" runat="server" width="100%"
                 DayField="EventDate" >

        <b><%# Container.DataItem["EventTime"] %></b>
        <%# Container.DataItem["EventTitle"] %>


Data binding expressions <%# . . . %> should be resolved as the template is applied. To support this feature we need to define a container object for the calendar item. The syntax Container.DataItem["..."] refers to a DataItem property of this container object. Given that the source for the DataCalendar is a DataTable object, the DataItem property (a single item within the source) will logically be of type DataRow. The following code shows the class DataCalendarItem defined to serve as this container object:

public class DataCalendarItem : Control, INamingContainer

    private DataRow _dataItem;

    public DataCalendarItem(DataRow dr) {
        _dataItem = dr;

    public DataRow DataItem {
       get {return _dataItem;}
       set {_dataItem = value;}

DataCalendarItem implements the INamingContainer interface, a requirement for template containers. This ensures that control names remain unique when templates are applied through multiple iterations of data items.

The next step is to define the ItemTemplate property in the DataCalendar class. This property is of type ITemplate, and is marked with the attribute TemplateContainer. The TemplateContainer attribute identifies which class will function as the container for an instance of the template. In our case, this will be the DataCalendarItem we just defined.

public class DataCalendar : Calendar, INamingContainer
    private ITemplate _itemTemplate;

    public ITemplate ItemTemplate
        get {return _itemTemplate; }
        set {_itemTemplate = value;}

With these template definitions, we can now return to the OnDayRender method of the DataCalendar class. Each iteration through the data source gives us a single calendar item in the form of a DataRow. With that item we need to perform the following tasks:

  1. Create a container DataCalendarItem object, constructed with the item's DataRow
  2. Instantiate the ItemTemplate in the container (using the ITemplate.InstantiateIn() method)
  3. Execute the DataBind method of the DataCalendarItem object to resolve data binding expressions (this method is inherited from Control)
  4. Add the DataCalendarItem control to the TableCell that represents the given day

These tasks are handled through the private helper function SetupCalendarItem, which is executed from OnDayRender once for each calendar item:

private void SetupCalendarItem(TableCell cell, DataRow r, ITemplate t)
    // given a calendar cell and a datarow, set up the
    // templated item and resolve data binding syntax
    // in the template
    DataCalendarItem dti = new DataCalendarItem(r);

protected override void OnDayRender(TableCell cell, CalendarDay day)
    if (_dtSource != null)
        // are there events on this day?
        if (dv.Count > 0) {
            // for each event on this day apply the
            // ItemTemplate, with data bound to the item's row
            // from the data source
            if (this.ItemTemplate != null)
                for (int i=0; i<dv.Count; i++) {
                    SetupCalendarItem(cell, dv[i].Row,
            // no events this day;

With support for an ItemTemplate in place, it is a simple matter to implement a NoEventsTemplate as well, also instantiated from the OnDayRender method. If a day in the data source has no calendar items, the NoEventsTemplate is applied.

    // no events this day;
    if (this.NoEventsTemplate != null)
        SetupCalendarItem(cell, null,



As described before, a downside of the approach of sub-classing the Calendar control is that events from controls in our templates will not fire. A great upside to this approach however is the strong support the Calendar control offers for styles. Without any more code, we can make use of the properties DayStyle, TodayDayStyle, WeekdayDayStyle, OtherMonthDayStyle, and several others to customize the calendar's appearance.

In the DataCalendar class we will define one more data-relevant property of type TableCellStyle: DayWithEventsStyle. This property is applied in the OnDayRender event for each day that has data items. This allows the page designer the ability, for example, to set a different background color for days with events. The following shows the relevant code from DataCalendar to support DayWithEventsStyle:

public class DataCalendar : Calendar, INamingContainer
    private TableItemStyle _dayWithEventsStyle;

    public TableItemStyle DayWithEventsStyle {
        get {return _dayWithEventsStyle;}
        set {_dayWithEventsStyle = value;}

    protected override void OnDayRender(TableCell cell, CalendarDay day)
        if (_dtSource != null)
            // are there events on this day?
            if (dv.Count > 0) {
                // there are events on this day; if indicated,
                // apply the DayWithEventsStyle to the table cell
                if (this.DayWithEventsStyle != null)



About the Examples

The examples in the sample project demonstrate different applications of the DataCalendar control. Since the displayed entries are not maintained through ViewState (as would be typical of a true data-bound control) other means of caching the calendar data are offered, including Session variables and the application Cache.


This example uses a DataTable object constructed in code, and shows a simple DataCalendar without much formatting.


This example demonstrates using data from an OLEDB data source, in this case an Access table. The <ItemTemplate> of this DataCalendar displays a hyperlink for each event, with a small image identifying the event category. The data source is cached in a Session variable.


The data source for this example is an XML document, using the XmlDataDocument class to get to the DataTable. This DataCalendar uses a little more formatting than the previous two. After loading, the data source is stored in the application Cache.


This example uses an OLEDB data source, without caching the results. Instead, the data source is queried with each postback, but a SQL Where clause limits the results to events for the displayed month.


This example shows the DataCalendar functioning more like a regular Calendar for selecting a date. No <ItemTemplate> is used, but the DayWithEventsStyle attribute is applied to highlight those days with events. A Repeater control is used to display events for the selected date.


The existing ASP.NET Calendar control is great for selecting dates but lacks data binding support. Sub-classing the Calendar control and overriding the OnDayRender method can simulate such support. Though controls that fire events can't be included in day cells using this approach, static content may be used as can the full contingent of Style properties inherited from the Calendar control. The DataCalendar class presented here may be used for displaying items from a DataTable, with layout customized by page designers through the use of its ItemTemplate and NoEventsTemplate properties. The DataCalendar class may itself serve as a base class for additional database-specific implementations.


  • 6 Feb 2004
- Updated to include support for DataSet objects and added the DataMember property; also updated OnDayRender() to better handle internationally formatted dates and dates with time values.
  • 3 Nov 2003
- Original posting


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


About the Author

Mike Ellison
United States United States
I work for the University of Nevada, Las Vegas in the Office of Institutional Analysis and Planning. Among other things, our office is charged with the mission of deriving useful information in support of administrative decision-making from institutional data. Within the context of that mission, my office mates and I apply technology in the form of custom data processing applications, data extraction and analysis tools, reporting tools, relational databases, OLAP solutions, data warehousing, and data mining.

Visit my blog at

You may also be interested in...

Comments and Discussions

QuestionMy vote of 5 Pin
Member 1199207118-Sep-15 5:45
memberMember 1199207118-Sep-15 5:45 
SuggestionMultiple day events Pin
Member 101360225-Jul-13 0:28
memberMember 101360225-Jul-13 0:28 
QuestionNeed code for getting calendars to show or hide events Pin
Member 100289054-May-13 8:22
memberMember 100289054-May-13 8:22 
QuestionI'm new Pin
Member 100276494-May-13 2:21
memberMember 100276494-May-13 2:21 
AnswerRe: I'm new Pin
Mike Ellison4-May-13 2:46
memberMike Ellison4-May-13 2:46 
QuestionSource code Pin
Boipelo16-Aug-12 23:02
memberBoipelo16-Aug-12 23:02 
AnswerRe: Source code Pin
Mike Ellison17-Aug-12 5:09
memberMike Ellison17-Aug-12 5:09 
GeneralMy vote of 5 Pin
jpratik22-Jun-12 3:39
memberjpratik22-Jun-12 3:39 
QuestionDataCalander for Windows Form Pin
djmak8-Apr-12 20:47
memberdjmak8-Apr-12 20:47 
AnswerRe: DataCalander for Windows Form Pin
Mike Ellison9-Apr-12 3:31
memberMike Ellison9-Apr-12 3:31 
QuestionAdd a button on day render = doesn't fire Pin
DeWaRs120620-Feb-12 9:06
memberDeWaRs120620-Feb-12 9:06 
AnswerRe: Add a button on day render = doesn't fire Pin
DeWaRs120620-Feb-12 9:25
memberDeWaRs120620-Feb-12 9:25 
GeneralMy vote of 5 Pin
manoj kumar choubey7-Feb-12 19:29
membermanoj kumar choubey7-Feb-12 19:29 
QuestionEvent on multiple day Pin
DeWaRs12066-Oct-11 22:19
memberDeWaRs12066-Oct-11 22:19 
AnswerRe: Event on multiple day Pin
Mike Ellison7-Oct-11 5:32
memberMike Ellison7-Oct-11 5:32 
GeneralRe: Event on multiple day Pin
DeWaRs120620-Feb-12 9:07
memberDeWaRs120620-Feb-12 9:07 
QuestionAm I missing something? downloaded demo and do not know how to start it. no default.aspx... Pin
androidiscool10-Sep-11 4:54
memberandroidiscool10-Sep-11 4:54 
AnswerRe: Am I missing something? downloaded demo and do not know how to start it. no default.aspx... Pin
Mike Ellison12-Sep-11 5:51
memberMike Ellison12-Sep-11 5:51 
Questionthank you ! Pin
wzoras19-Aug-11 2:05
memberwzoras19-Aug-11 2:05 
AnswerRe: thank you ! Pin
Mike Ellison26-Aug-11 11:52
memberMike Ellison26-Aug-11 11:52 
GeneralGreat! Pin
NorbyTheGeek9-Jun-11 4:46
memberNorbyTheGeek9-Jun-11 4:46 
QuestionIs it possible to define the Culture of the Calendar ? Pin
sot1925_19849-May-11 22:37
membersot1925_19849-May-11 22:37 
GeneralMy vote of 5 Pin
Member 374225211-Feb-11 1:31
memberMember 374225211-Feb-11 1:31 
GeneralDynamically add ItemTemplate Pin
Member 37422529-Feb-11 3:04
memberMember 37422529-Feb-11 3:04 
GeneralRe: Dynamically add ItemTemplate Pin
Mike Ellison9-Feb-11 5:59
memberMike Ellison9-Feb-11 5:59 
GeneralRe: Dynamically add ItemTemplate Pin
Member 37422529-Feb-11 22:03
memberMember 37422529-Feb-11 22:03 
GeneralRe: Dynamically add ItemTemplate Pin
Mike Ellison10-Feb-11 12:47
memberMike Ellison10-Feb-11 12:47 
GeneralRe: Dynamically add ItemTemplate Pin
Mike Ellison10-Feb-11 13:31
memberMike Ellison10-Feb-11 13:31 
GeneralRe: Dynamically add ItemTemplate Pin
Member 374225210-Feb-11 22:15
memberMember 374225210-Feb-11 22:15 
GeneralRe: Dynamically add ItemTemplate Pin
Mike Ellison11-Feb-11 6:47
memberMike Ellison11-Feb-11 6:47 
GeneralRe: Dynamically add ItemTemplate Pin
Rod DeValcourt29-Nov-12 10:40
memberRod DeValcourt29-Nov-12 10:40 
QuestionNew to .net Pin
kittygirl70723-Dec-10 17:22
memberkittygirl70723-Dec-10 17:22 
AnswerRe: New to .net Pin
kittygirl7075-Jan-11 15:23
memberkittygirl7075-Jan-11 15:23 
AnswerRe: New to .net Pin
Mike Ellison6-Jan-11 10:39
memberMike Ellison6-Jan-11 10:39 
AnswerRe: New to .net Pin
Mike Ellison10-Feb-11 13:34
memberMike Ellison10-Feb-11 13:34 
Questionhow to get selected month when paging the calender Pin
Mihaly Sogorka22-Jul-10 4:11
memberMihaly Sogorka22-Jul-10 4:11 
AnswerRe: how to get selected month when paging the calender Pin
Mike Ellison26-Jul-10 6:01
memberMike Ellison26-Jul-10 6:01 
GeneralRe: how to get selected month when paging the calender Pin
Mihaly Sogorka26-Jul-10 6:02
memberMihaly Sogorka26-Jul-10 6:02 
Generalnot taking USING SYSTEM.UI.WEB; assembly Pin
ravi.928814-Apr-10 0:53
memberravi.928814-Apr-10 0:53 
GeneralRe: not taking USING SYSTEM.UI.WEB; assembly Pin
Mike Ellison14-Apr-10 6:07
memberMike Ellison14-Apr-10 6:07 
Questioncan i use this in my project Pin
ravi.928813-Apr-10 21:53
memberravi.928813-Apr-10 21:53 
AnswerRe: can i use this in my project Pin
Mike Ellison14-Apr-10 5:52
memberMike Ellison14-Apr-10 5:52 
QuestionFramework 3.5 ? Pin
Sicilian200025-Mar-10 8:28
memberSicilian200025-Mar-10 8:28 
AnswerRe: Framework 3.5 ? Pin
Mike Ellison14-Apr-10 6:04
memberMike Ellison14-Apr-10 6:04 
AnswerRe: Framework 3.5 ? Pin
Davidzongo1-Sep-10 16:56
memberDavidzongo1-Sep-10 16:56 
QuestionCannot get it to work. Can somebody help? Pin
boria23-Mar-10 5:11
memberboria23-Mar-10 5:11 
AnswerRe: Cannot get it to work. Can somebody help? Pin
Mike Ellison23-Mar-10 15:09
memberMike Ellison23-Mar-10 15:09 
GeneralMembers Pin
christopher.x.baker17-Mar-10 10:08
memberchristopher.x.baker17-Mar-10 10:08 
GeneralRe: Members Pin
Mike Ellison17-Mar-10 13:32
memberMike Ellison17-Mar-10 13:32 
GeneralGetting the calendar to print Pin
angelzion21-Feb-10 19:51
memberangelzion21-Feb-10 19:51 

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

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

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170713.1 | Last Updated 20 Feb 2004
Article Copyright 2003 by Mike Ellison
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid