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

DataCalendar

By , 19 Feb 2004
 

Introduction

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.

Background

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;}
            set 
            {
                if (value is DataTable || value is DataSet) 
                    _dataSource = value;
                else
                    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];
                    else
                        // 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.
            base.Render(html);
        }

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}#", 
                   this.DayField, 
                   day.Date.ToString("MM/dd/yyyy"), 
                   day.Date.AddDays(1).ToString("MM/dd/yyyy")
                );
               
                // are there events on this day?
                if (dv.Count > 0) {
                    // there are events on this day;
                    .
                    .
                    .
                }
                else
                {
                    // 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" >

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

     </dc:DataCalendar>

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;
       
        [TemplateContainer(typeof(DataCalendarItem))]   
        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);
        t.InstantiateIn(dti);
        dti.DataBind();
        cell.Controls.Add(dti);           
    }    


    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,
                                          this.ItemTemplate);
                    }
            }
            else
            {
                // 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.

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

Styles

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)
                        cell.ApplyStyle(this.DayWithEventsStyle);
                    .
                    .
                    .
                }
                else
                {
                    .
                    .
                    .                        
                }               
                 
            }           
            .
            .
            .
        }                  
   
    }

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.

DataCalendar1.aspx

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

DataCalendar2.aspx

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.

DataCalendar3.aspx

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.

DataCalendar4.aspx

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.

DataCalendar5.aspx

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.

Summary

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.

History

  • 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

License

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 MishaInTheCloud.com


Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionNeed code for getting calendars to show or hide eventsmemberMember 100289054-May-13 8:22 
I trying to get a calendar web app for my school that will show multiple calendars based on what the user whats to see, for example if the user was in tech club and on the football teem he/she would be able to see both the footbal and tech club events in one calendar but becaue he/she is not in drama club that would not show. i would be truly gratful for someone who can show me the code needed to do this?
QuestionI'm newmemberMember 100276494-May-13 2:21 
this might sound lame but how do i get the code to show me a calendar in a web site
AnswerRe: I'm newmemberMike Ellison4-May-13 2:46 
Hi there. Among the files you can download with this article are examples you may inspect to see how the DataCalendar control may be applied. Take a look at those, and see if that gets you started.

QuestionSource codememberBoipelo16-Aug-12 23:02 
Where can I download the source code, I only see page - I was hoping to run and test it. The solution file?
I remain joe!

AnswerRe: Source codememberMike Ellison17-Aug-12 5:09 
Hi Joe. The source is in the file datacalendar_src.zip : DataCalendar.cs. There's also a build.bat file in there to compile the source to a .dll. This article pre-dates my use of Visual Studio; I was doing a lot of coding in a text-editor and compiling through the command line back then.

GeneralMy vote of 5memberjpratik22-Jun-12 3:39 
Awwsome! almost like google calendar!
QuestionDataCalander for Windows Formmemberdjmak8-Apr-12 20:47 
Is this DataCalendar Available for windows Form ????
http://hackwithmak.blogspot.com

AnswerRe: DataCalander for Windows FormmemberMike Ellison9-Apr-12 3:31 
This article is about a data calendar implementation for asp.net 2.0. I don't know if someone has posted anything similar for winforms.

QuestionAdd a button on day render = doesn't firememberDeWaRs120620-Feb-12 9:06 
Hello,
 
Thank you for this cool code, I just have one question : I want to put some button inside the calendar, but it doesnt fire. Did you know why ? Did you have a solution ?
 
Regards
 
DeWaRs
AnswerRe: Add a button on day render = doesn't firememberDeWaRs120620-Feb-12 9:25 
Hello,
 
I have read more carefully your article and I have my answer Wink | ;)
Thanks again for your wonderfull work !
GeneralMy vote of 5membermanoj kumar choubey7-Feb-12 19:29 
Nice
QuestionEvent on multiple daymemberDeWaRs12066-Oct-11 22:19 
Hello,
 
First, thank you for this very good project. I have just a question, I have some appointment which must be deplay in multiple day. In my database I have a "StartDate" collumn and "EndDate" colum and I want to display it on all the day between startdate and Enddate.
I don't know how to do that :s
Did anyone already do that ?
 
Regards
 
Emmanuel
AnswerRe: Event on multiple daymemberMike Ellison7-Oct-11 5:32 
Hi there. Thanks for the kind words. You can review this previous message[^] which I think answers your question.

GeneralRe: Event on multiple daymemberDeWaRs120620-Feb-12 9:07 
Hello,
 
Thanks for the solution, I have create manually a datatable and it works fine.
 
Regards
 
Emmanuel
QuestionAm I missing something? downloaded demo and do not know how to start it. no default.aspx...memberandroidiscool10-Sep-11 4:54 
I tried to run every aspx and just got errors.
 
HELP
 
thanks
AnswerRe: Am I missing something? downloaded demo and do not know how to start it. no default.aspx...memberMike Ellison12-Sep-11 5:51 
I'm missing something in your post. I'm guessing you posted detailed information about the errors you were seeing (the kind of information that would make it possible to provide help) and it just never made it to CP's servers?

Questionthank you !memberwzoras19-Aug-11 2:05 
Hello, I am really happy, that I found this article, its very useful. Anyway is here any way to select more days when my event is longer more than one day ? I have start / end date in DB and I really dont know how to select days between my start / end days.
 
Thanks for any sugestion. I have not idea how to do that Smile | :)
AnswerRe: thank you !memberMike Ellison26-Aug-11 11:52 
Hi there. Thanks for the nice comments.
 
There really isn't anything in the coding I supplied for the article to support multi-day events. When I've used the code myself, I've always interpreted my multi-day events (in the query I've used to retrieve events) in such a way as to ensure multiple rows for those events - so the same event would repeat for each day in my result set. It occurs to me that because that strategy worked well, I never ended up having to modify the DataCalendar to build such support there.
 
I hope that suggestion might be helpful though.

GeneralGreat!memberNorbyTheGeek9-Jun-11 4:46 
This was just what we needed for a project. Easy to implement and customize. Thanks!
QuestionIs it possible to define the Culture of the Calendar ?membersot1925_19849-May-11 22:37 
Hi there, i am using your control for some time now and everything work great.(project in .net 1.1)
I now have to change the culture of the calendar (define it) Is that possible and how do you recommend that i implement this. Thank you.
GeneralMy vote of 5memberMember 374225211-Feb-11 1:31 
Very helpfula nd easy to implement.
GeneralDynamically add ItemTemplatememberMember 37422529-Feb-11 3:04 
How can I add the itemItemplate from code-behind dynamically?
Reason: I want to use DataCalendar.cs as a class file in my project and not as a dll reference.
I do not want to use the "Register" tag but use DataCalendar as a class file.
Pls give me directions on the above.
GeneralRe: Dynamically add ItemTemplatememberMike Ellison9-Feb-11 5:59 
Hi there. If you are using the DataCalendar as a .cs class file in the APP_CODE directory rather than using the compiled .dll, you probably still can use markup instead of code-behind to create your item templates (which I think would be easier and more desirable). I've read that there is a form of the @Register directive that allows for this. See this previous response[^] for that information and let me know how it works for you.

GeneralRe: Dynamically add ItemTemplatememberMember 37422529-Feb-11 22:03 
Thank you Mike. I tried the approach as per your suggestion. Added a @Register tag and placed my .cs file in the App_code folder. I added the markup as per the samples. But the application does not identify the "cal1" =>ID for the control
error: Cal1 does not exist in current context.
Anyhting that I am missing??
 
Another approach that I was trying was to load ItemTemplate through "LoadTemplate" method. But I hit a wall there too.
Problem here: I created a ascx file and added the markup for the ItemTemplate.
In my code I called:
DataControls.DataCalendar dc = new DataControls.DataCalendar()
dc.ItemTemplate = Page.LoadTemplate("MyTemp.ascx");
Error: Parser error in ascx file indicating that "DataItem" is not identified.
 
Can you pls tell me how I could add the ItemTemplate through code.
Ex:
DataControls.DataCalendar dc = new DataControls.DataCalendar()
dc.ItemTemplate = ???????

 
Regards
GeneralRe: Dynamically add ItemTemplatememberMike Ellison10-Feb-11 12:47 
I was trying the @Register method with declarative template and the .cs file in the APP_CODE directory, and having issues myself (though the documentation says it is possible, I haven't gotten it to work that way). I'll look into this and see what I can come up with for programmatic creation of the template.

GeneralRe: Dynamically add ItemTemplatememberMike Ellison10-Feb-11 13:31 
Okay, here's something you can try. Start with the DataCalendar.cs file in your APP_CODE directory. Then create a simple WebForm like this:
    <form id="form1" runat="server">
      <div>
    
        <asp:PlaceHolder ID='phCalendar' runat="'server'" />
        
      </div>
    </form>
To construct an item template in code, you need to create a class that implements ITemplate. (You can Google or MSDN it for more information on implementing ITemplate). In my example, I just included this class, SampleTemplate, in the code-behind for the page, but I imagine it can be stand-alone in APP_CODE too:
    public class SampleTemplate : ITemplate
    {
        // Implementation of ITemplate
        public void InstantiateIn(System.Web.UI.Control container)
        {
            // Create a label that will be eventually bound to the event title
            Label lbl = new Label();
            lbl.ID = "EventTitle";
 
            // establish databinding for the label
            lbl.DataBinding += new System.EventHandler(this.BindEventTitle);
 
            // Make the label appear in the container
            container.Controls.Add(lbl);
        }
 
        private void BindEventTitle(object sender, EventArgs e)
        {
            Label lbl = (Label)sender;
 
            // the container for the label is a DataCalendarItem object
            DataCalendarItem container = (DataCalendarItem) lbl.NamingContainer;               
 
            // we know the source is a DataTable, so we'll cast the data item to a DataRow
            // could probably use DataBinder.Eval instead for more generic handling
            DataRow r = (DataRow) container.DataItem;
 
            // now bind the event title text
            lbl.Text = "<br />" + r["EventTitle"].ToString();
 
            // and also set the label color
            lbl.ForeColor = (System.Drawing.Color) r["Color"];
 
        } 
 
    }
The only ITemplate method you need to implement is InstantiateIn, which is called for each item of data in the template. You can see in my example I am only adding a single Label control in the template. But - I am also setting its DataBinding event to a custom event handler in the class, BindEventTitle(). This private method populates the label with the event title text and sets the color according to the datasource.
 
In the Load event for the page then, I create the dataCalendar, place it on the page (in a PlaceHolder control), assign it the SampleTemplate, call a method to receive its datasource, and finally bind the data:
        protected void Page_Load(object sender, EventArgs e)
        {
            // create the calendar, identify the "EventDay" data field as supplying 
            // the day, and establish the ItemTemplate
            DataCalendar dc = new DataCalendar();
            phCalendar.Controls.Add(dc);
            dc.DayField = "EventDay";
            dc.ItemTemplate = new SampleTemplate();            
 
            // get the data source and bind it
            dc.DataSource = GetEventData();
            dc.DataBind();
 
        }
 
I reused the GetEventData() function from the original Calendar1.aspx sample, but I'll include it below too:
        DataTable GetEventData()
        {
            DataTable dt = new DataTable();
 
            dt.Columns.Add("EventTitle", typeof(String));
            dt.Columns.Add("EventDay", typeof(DateTime));
            dt.Columns.Add("Color", typeof(System.Drawing.Color));
 
            DataRow r = dt.NewRow();
            r["EventTitle"] = "Today's Event";
            r["EventDay"] = System.DateTime.Today;
            r["Color"] = System.Drawing.Color.Black;
            dt.Rows.Add(r);
 
            r = dt.NewRow();
            r["EventTitle"] = "Tomorrow's Event";
            r["EventDay"] = System.DateTime.Today.AddDays(1);
            r["Color"] = System.Drawing.Color.Red;
            dt.Rows.Add(r);
 
            r = dt.NewRow();
            r["EventTitle"] = "Tomorrow's Event #2";
            r["EventDay"] = System.DateTime.Today.AddDays(1);
            r["Color"] = System.Drawing.Color.Blue;
            dt.Rows.Add(r);
 
            r = dt.NewRow();
            r["EventTitle"] = "Next Week's Event";
            r["EventDay"] = System.DateTime.Today.AddDays(7);
            r["Color"] = System.Drawing.Color.Green;
            dt.Rows.Add(r);
 
            return dt;
        }
I hope this is helpful.
--mike

GeneralRe: Dynamically add ItemTemplatememberMember 374225210-Feb-11 22:15 
Thanks Mike.
This worked well and I am able to run my sample without errors.
But if I see the source code for Datacalendar.cs, I see that we have similar thing there to apply the
ItemTemplate. Therefore can you pls share your thoughts on why do we need to repeat this process of implementing ITempate interface in my sample?
Is there a possibility of using Page.LoadTemplate() with your sample. I tried it but ran into certain issues.
 
Thanks a lot for your time. Your posts have been very helpful.
GeneralRe: Dynamically add ItemTemplatememberMike Ellison11-Feb-11 6:47 
Hi there. What you are seeing in the control code is the DataCalendar control calling the InstantiateIn method during item creation. What you have done in creating a class that implements ITemplate is allow controls like DataCalendar (and any other templated controls) access to your InstantiateIn method, so items may be created from your custom template.
 
Does that make sense? Put another way: for templating to work, the control object and the template object have to work together. They do this by each respecting the ITemplate contract: the template object implements the contract, while the control object relies on it when creating items corresponding to data.
 
Page.LoadTemplate() can be used in these kinds of situations, but probably not for the DataCalendar as it is currently written. LoadTemplate() returns an ITemplate object, so you can use it to programmatically load a template for a templated control. Typically though, a templated control will support additional events, like ItemCreated and ItemDataBound, so that when the loaded declarative template gets instantiated in an item, you can programmatically assign control values as databinding occurs. The problem here is that the DataCalendar does not support events like that, partly due to the fact that it is inheriting from Calendar and performing its simulated databinding in the Render event (which calls OnDayRender(), which actually performs the work). I think you'd run into errors if you tried to assign databinding expressions declaratively in the template .ascx control itself, which is too bad, because having binding expressions in the template itself would simplify this a lot.
 
So... having to perform this all from .cs code leaves you I think with two options: you may use the custom ItemTemplate class concept (like the SampleTemplate coding I demonstrated earlier), or you will likely have to manually override the Calendar's Render event (or the DataCalendar's OnDayRender method) and manually create and set the controls according to the data source. This latter option effectively bypasses using an ItemTemplate altogether, really.
 
I hope this is helpful.

GeneralRe: Dynamically add ItemTemplatememberRod DeValcourt29-Nov-12 10:40 
Page cannot be null. Please ensure that this operation is being performed in the context of an ASP.NET request.
 
it's on a webpage....
Rod DeValcourt
MCAD, MCSD, MCDBA

QuestionNew to .netmemberkittygirl70723-Dec-10 17:22 
Hi there-
I love what you've done with the calendar! I need more customization though and need to do it in the source file DataCalendar.cs. Also, I don't want to have to use a .dll (web hosting issue). Because I'm new to .net I'm having a rough time figuring out what code to put where, e.g., use a Class file, etc.
 
1. I converted the content inside DataCalendar.cs to .vb and saved in a new class file in the /App_Code/ folder and named it DataControls.vb
2. I dropped the VB code from your .aspx page into the code-behind file Calendar.aspx.vb
3. I dropped the html code from your .aspx page into the correct content placeholder control
4. I tried modifying the @Register command to use the new class file but it's still not recognizing the tag prefix:
<%@ Register Namespace="DataControls" Src="~/App_Code/DataControls.vb" TagPrefix="dc" %>
 
Any suggestions for a newb?
 
thanks!
~dominique
AnswerRe: New to .netmemberkittygirl7075-Jan-11 15:23 
Any body out there? I still need a hand with this...
AnswerRe: New to .netmemberMike Ellison6-Jan-11 10:39 
Hi there Dominique. I haven't tried this myself, so you'll have to let me know if either of these suggestions work for you. According to .NET documentation[^], you are supposed to be able to use the @Register directive without an Assembly attribute (or in your case, I think without a Src attribute) and the parser will assume the class is defined in the App_Code directory... like this:
<%@ Register tagprefix="tagprefix" namespace="namespace" %>
I have also read posts that suggest using __code (two underscores) as the Assembly attribute:
<%@ Register TagPrefix="ABC" Namespace="ABC.Foo" Assembly="__code" %>
.
 
Let me know if either of those work for you.

AnswerRe: New to .netmemberMike Ellison10-Feb-11 13:34 
Hi Dominique. In my experimentation, I've been having problems getting the @Register to work with the DataCalendar.cs file saved in app_code. Were you able to get it working that way?
 
As an alternative, I worked out an example of using a DataCalendar and setting its ItemTemplate programmatically rather than declaratively. If it's of interest to you, you can find it
as a response to another message[^] on this forum.

Questionhow to get selected month when paging the calendermemberMihaly Sogorka22-Jul-10 4:11 
Hi!
First thanks for this useful control!
 
Is there any way to handle somehow the OnChange event of your calendar's Next/Prev month selector.
The main goal is to get the selected month when user clicks on Next/Prev month on the calendar.
Something like this:
 
protected void DataCalendar_NextPrevButtonChanged(object sender, EventArgs e)
{
  Response.Write("<script>alert('" + cal1.SelectedMonth + "')</script>");
}
 
I know the above code won't work, because there is no such an event like 'NextPrevButtonChanged' and the 'SelectedMonth' is also unavailable. But the code shows what I want to approach.
Any idea?
AnswerRe: how to get selected month when paging the calendermemberMike Ellison26-Jul-10 6:01 
What about using the VisibleMonthChanged[^] property?

GeneralRe: how to get selected month when paging the calendermemberMihaly Sogorka26-Jul-10 6:02 
Thanks, that worked
Generalnot taking USING SYSTEM.UI.WEB; assemblymemberravi.928814-Apr-10 0:53 
it giving error while adding like saying mising USING SYSTEM.UI.WEB AND HOW CAN I ADD REFERENCE
GeneralRe: not taking USING SYSTEM.UI.WEB; assemblymemberMike Ellison14-Apr-10 6:07 
Hmmm... have you done much ASP.NET development before?

Questioncan i use this in my projectmemberravi.928813-Apr-10 21:53 
can i use this in my project
AnswerRe: can i use this in my projectmemberMike Ellison14-Apr-10 5:52 
Sure. Why not? It's licensed under the CodeProject Open License[^].

QuestionFramework 3.5 ?memberSicilian200025-Mar-10 8:28 
Can this control be used in a .net framework 3.5 ?
 
Thanks!
AnswerRe: Framework 3.5 ?memberMike Ellison14-Apr-10 6:04 
Yup.

AnswerRe: Framework 3.5 ?memberDavidzongo1-Sep-10 16:56 
Sure
It is pretty coool
It is not because things are difficult that we do not dare; it is because we do not dare that they are difficult.
Seneca(Roman dramatist, philosopher, & politician (5 BC - 65 AD))
http://www.filsdufaso.com

QuestionCannot get it to work. Can somebody help?memberboria23-Mar-10 5:11 
Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately.
 
Parser Error Message: Unknown server tag 'dc:DataCalendar'.
 
Source Error:
 

Line 57: <h3>Events DataTable constructed through code</h3>
Line 58:
Line 59: <dc:DataCalendar id="cal1" runat="server" width="100%"
Line 60: DayField="EventDay" >
Line 61: <ItemTemplate>

 
Source File: /DataCalendar1.aspx Line: 59
Thank you. Ben

AnswerRe: Cannot get it to work. Can somebody help?memberMike Ellison23-Mar-10 15:09 
Ben, this is the error you get if you do not register a custom control for use on your page. You would add the following to the top of your .aspx page:
 
<% @Register Namespace="DataControls" Assembly="DataCalendar" TagPrefix="dc" %>
 
You'll see that on the samples that come with the article.

GeneralMembersmemberchristopher.x.baker17-Mar-10 10:08 
Does a list of members (properties et al.) exist?
 
I'm going to make good use of this awesome tool in a project I'm building and would like to know everything it can do.
 
Thanks for sharing it with us!
GeneralRe: MembersmemberMike Ellison17-Mar-10 13:32 
Hi there. Well, there isn't a .chm help file or anything like that for it, but the code is fairly short and simple (in the DataCalendar.cs file), and if you read the article you should have a good handle on how to work with it.
 
Being a subclass of the Calendar[^] control, you can access all the Calendar's properties. DataCalendar only adds the DataSource, DataMember, DayField data properties, the DayWithEventsStyle style property, and the template properties ItemTemplate and NoEventsTemplate for data display.
GeneralGetting the calendar to printmemberangelzion21-Feb-10 19:51 
I am trying to get the rows to print on the same page. When the calendar prints if the month is long due to many events it my split the week were you can see some events for the day on one page and the rest on the next. Is there a way to make the table row that is being printed on to pages just print on the second page. I am not sure if I am being clear.
 
Dan
GeneralRe: Getting the calendar to printmemberMike Ellison1-Mar-10 6:45 
Hi Dan. That's more a function of the browser's print capability, whether or not table cells are "broken" across pages. You can force a page break through css, like this:
<tr style="page-break-after: always;">
but I don't think that really helps in your case.
Generalvery nice ~member박희수13-Jan-10 20:31 
Laugh | :laugh: Thumbs Up | :thumbsup:
 
thank you

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

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