Click here to Skip to main content
Click here to Skip to main content
Go to top

Cool Calendar - Amazing Calendar without popup

, 11 Oct 2004
Rate this:
Please Sign up or sign in to vote.
This article will show you how to build a cool Calendar without out popups and PostBack events. You even don't have to write a single line of JavaScript code.

Sample Image - CoolCalendarImg.jpg

Introduction

I would like to thank Microsoft for shipping Calendar control in .NET that helps us to solve many problems, but it has many limitations and drawbacks. I have seen many articles just to improve this control. Many articles suggest Popup window. but I found that many users don't like popups. Second, we have to write JavaScript to deal with it. Second problem with Calendar control itself is it doesn't provide navigation by year. Imagine when you have to enter some date of 10 years back. Even for 2 years, user has to click at least 24 times and so 24 round trips. Even for same year but 10 months back, at least 10 round trips. I was annoyed with this fact and started thinking about a better solution. At last, I have listed out the requirement for the best calendar.

  • It should provide navigation for month as well as year.
  • It should provide combobox for month as well as year to select past dates.
  • It should not appear as popup.
  • It should occupy as little as possible space on the form.
  • It should assign value to control automatically, no JavaScript need to be written.

And here we go, I have tried my best to fulfill all the above requirements in this article.

Hope it will be useful to you.

Using the code

As I said, there is no need to write a single line of JavaScript code any more. Add a reference of CoolCalendar control in toolbox. Just drag the control on the page, assign the control (control to which, you want to assign the value) to CoolCalander, and enjoy...!!!!!!!!!!!!!

Points of Interest

Sounds interesting...!!! So, let's start exploring the magic behind this control. It is a composite control. It's a combination of Label(s), LinkButton(s) and a Calendar control. As it's a composite control, I have derived my class from Control class. First, list out the points that we have to keep in mind:

  • We need navigation button for previous, next month as well as year.
  • We need dropdown box for year as well as month, but it should display only when user clicks on month or year..!!
  • We need calendar, without postback event on each day.
  • Define the property which can take reference of the control to assign selected date.
  • Define the property to specify date format.
  • The control should occupy less space on the page.

Core of control

As this is a composite control, we need not implement/ override Render method. In fact, the main core function of the control is CreateChildControls. So, whenever the control is initialized, it will call this method after Init and before PreRender events. I have created all my child controls here. The code is self explanatory.

protected override void CreateChildControls() {
    Calendar cal=new Calendar(); 

    //Default Diplay Current Month
    cal.VisibleDate=DateTime.Today; 
    //disable default heading
    cal.ShowTitle=false; 
    cal.BackColor=BackColor; 
    cal.ForeColor=ForeColor; 
    cal.Attributes.Add("style","z-index:0"); 

    // By Default control will be render as small text or small Image.
    // Onclick on this text/image only our calander will be displayed
    if(ViewState["visibility"]==null) 
        ViewState["visibility"]=false;
    if(Img=="")
      Controls.Add(new 
         LiteralControl(@"<div style='position:absolute;z-index:0' id='"+ 
         this.ID+@":Div1' onClick=""ShowCal('"+this.ID+
         @":Cal')"">Select Date</div><div " + 
         @"style='position:absolute;z-index:0;BACKGROUND-COLOR:"+ 
         HeadingBackColor.Name  +";visibility:hidden' id='"+
         this.ID+@":Cal' ><table cellpadding=0 " + 
         @"cellspacing=0><tr><td vAlign=""middle"" align=center>"));
    else
      Controls.Add(new 
         LiteralControl(@"<div style='position:absolute;z-index:0' id='"+ 
         this.ID+@":Div1' onClick=""ShowCal('"+this.ID+ 
         @":Cal')""><img src='"+ Img + 
         "'></img></div><div " + 
         "style='position:absolute;z-index:0;BACKGROUND-COLOR:"+ 
         HeadingBackColor.Name +" ;visibility:hidden' id='"+this.ID+ 
         @":Cal' ><table cellpadding=0 " + 
         @"cellspacing=0><tr><td vAlign=""middle"" align=center>"));
    //<div style='position:absolute;left:15px;z-index:0'>Month</div>
    //<div style='position:absolute;z-index:0'>Year</div>

    DropDownList cboyear = new DropDownList();
    DropDownList cboMonth= new DropDownList();
    Label  lblMonth=new Label();
    Label lblYear=new Label();
    lblMonth.Text = cal.VisibleDate.ToString("MMMM").PadRight(12,' ')+",";
    lblYear.Text=cal.VisibleDate.ToString("yyyy");

    for(int i=2050;i>1049;i--)
        cboyear.Items.Add(i.ToString());   

    cboMonth.Items.Add("January");  
    cboMonth.Items.Add("February");  
    cboMonth.Items.Add("March");  
    cboMonth.Items.Add("April");  
    cboMonth.Items.Add("May");  
    cboMonth.Items.Add("Jun");  
    cboMonth.Items.Add("July");  
    cboMonth.Items.Add("Auguest");  
    cboMonth.Items.Add("September");  
    cboMonth.Items.Add("October");  
    cboMonth.Items.Add("November");  
    cboMonth.Items.Add("December");              

    cboMonth.AutoPostBack=true; 
    cboyear.AutoPostBack =true; 
    cboMonth.SelectedIndexChanged += new 
            EventHandler(cboMonth_SelectedIndexChanged);      
    cboyear.SelectedIndexChanged += new 
            EventHandler(cboyear_SelectedIndexChanged);             

    LinkButton  lblFirst=new LinkButton();
    LinkButton lblPrev=new LinkButton(); 
    LinkButton lblNext=new LinkButton(); 
    LinkButton lblLast=new LinkButton(); 

    lblFirst.Font.Name="Webdings";
    lblPrev.Font.Name="Webdings";
    lblNext.Font.Name="Webdings";
    lblLast.Font.Name="Webdings";

    lblFirst.Attributes.Add("style","TEXT-DECORATION: none;COLOR: "+ 
                                                  HeadingForeColor.Name);   
    lblPrev.Attributes.Add("style","TEXT-DECORATION: none;COLOR: "+ 
                                                  HeadingForeColor.Name); 
    lblNext.Attributes.Add("style","TEXT-DECORATION: none;COLOR: "+ 
                                                  HeadingForeColor.Name); 
    lblLast.Attributes.Add("style","TEXT-DECORATION: none;COLOR: "+ 
                                                  HeadingForeColor.Name); 

    //Tool tips to the Navigation Button
    lblFirst.Attributes.Add("title","Previous Year");   
    lblPrev.Attributes.Add("title","Previous Month");   
    lblNext.Attributes.Add("title","Next Month");   
    lblLast.Attributes.Add("title","Next Year");   

    lblPrev.Text="7";
    lblFirst.Text="9";
    lblNext.Text ="8";
    lblLast.Text=":"; 

    lblPrev.Click+=new EventHandler(lblPrev_Click);
    lblFirst.Click+=new EventHandler(lblFirst_Click);
    lblNext.Click+=new EventHandler(lblNext_Click);
    lblLast.Click+=new EventHandler(lblLast_Click);

    lblMonth.Attributes.Add("style","FONT-WEIGHT: bold; COLOR: "+ 
                                            HeadingForeColor.Name);    
    lblYear.Attributes.Add("style","FONT-WEIGHT: bold; COLOR:"+ 
                                            HeadingForeColor.Name);    

    Controls.Add(lblFirst); 
    Controls.Add(lblPrev); 
    //Controls.Add(cboMonth);
    //Controls.Add(cboyear);
    Controls.Add(lblMonth);
    Controls.Add(lblYear);

    // Hide Month and year dropdown box by defauld will be displayed
    // when user will click on month or year label.
    Controls.Add(new LiteralControl(@"<span style='width:"+ 
        200 +"px;background-color:white;position:absolute;left:10px;" + 
        "align:center;visibility:hidden;z-index:0' id='"+ 
        this.ID+ ":Month'>"));  
    Controls.Add(cboMonth);
    Controls.Add(cboyear);
    Controls.Add(new LiteralControl(@"</span>"));  
    Controls.Add(lblNext);
    Controls.Add(lblLast);
    lblMonth.Attributes.Add("OnClick","ShowCal('"+this.ID+@":Month')");   

    Controls.Add(new LiteralControl("</td></tr><tr><td>"));

    Controls.Add(cal);
    cal.DayRender+=new DayRenderEventHandler(cal_DayRender);
    Controls.Add(new LiteralControl("</td></tr></table></div>"));

}

We also need to register JavaScript to show / hide Calender control on user request. That we have to do on PreRender event. The code for PreRender is as follows:

protected override void OnPreRender(EventArgs e)
{
    base.OnPreRender (e);
    if((bool)ViewState["visibility"]==true)  
    {
        if(Img=="")
            ((LiteralControl)Controls[0]).Text= 
                 @"<div style='position:absolute;z-index:0' id='"+
                 this.ID+@":Div1' onClick=""ShowCal('"+this.ID+
                 @":Cal')"">Select Date</div><div style='position:" + 
                 @"absolute;z-index:0;BACKGROUND-COLOR:"+HeadingBackColor.Name + 
                 ";visibility:visible' id='"+this.ID+@":Cal' ><table " + 
                 @"cellpadding=0 cellspacing=0><tr>" + 
                 @"<td vAlign=""middle"" align=center>";
        else
            ((LiteralControl)Controls[0]).Text= 
                 @"<div style='position:absolute;z-index:0' id='"+this.ID+ 
                 @":Div1' onClick=""ShowCal('"+this.ID+@":Cal')""><img src='"+ 
                 Img +"'></img></div><div style='position:" + 
                 @"absolute;z-index:0;BACKGROUND-COLOR: "+HeadingBackColor.Name +
                 ";visibility:visible' id='"+this.ID+@":Cal' ><table " + 
                 @"cellpadding=0 cellspacing=0><tr>" + 
                 @"<td vAlign=""middle"" align=center>";
    }

    System.Text.StringBuilder strJavaScript=new System.Text.StringBuilder();

    //Code to emite Javascript that will display Calander.
    strJavaScript.Append(@"<script language="'JavaScript'">");

    strJavaScript.Append(@"function ShowCal(doc){alert(doc);" + 
        @" document.all[doc].style.visibility='visible';}</script>");

    Page.RegisterClientScriptBlock("CoolCalJavaScript", 
                                    strJavaScript.ToString());  

    //Code to emite Javascript that will assign Value to given control
    strJavaScript.Remove(0,strJavaScript.Length);

    strJavaScript.Append(@"<script language="'JavaScript'">");

    strJavaScript.Append(@"function AssignValue(ctrl,val,doc)" + 
           @"{ document.all[ctrl].value=val;document.all[doc]" + 
           @".style.visibility='hidden';}</script>");

    Page.RegisterClientScriptBlock("CoolCalJavaScript1", 
                                    strJavaScript.ToString());
}

Navigation Button

We need four navigation buttons. Navigation to previous year, previous month, next year, and next month. We need Click event to be trapped on server side as we want to change the visible date of the calendar according to button click.

/// <SUMMARY>
/// To Navigate to Previous Year
/// </SUMMARY>
private void lblPrev_Click(object sender, EventArgs e)
{
    Calendar cal=((Calendar)Controls[12]);
    cal.VisibleDate = cal.VisibleDate.AddMonths(-1);
    ViewState["visibility"]=true;     
    setLabel();
}

/// <SUMMARY>
/// To navigate to preveious Month
/// </SUMMARY>
private void lblFirst_Click(object sender, EventArgs e)
{
    Calendar cal=((Calendar)Controls[12]);
    cal.VisibleDate = cal.VisibleDate.AddYears(-1);
    ViewState["visibility"]=true;     
    setLabel();
}

/// <SUMMARY>
/// To Navigate to Next Month
/// </SUMMARY>
private void lblNext_Click(object sender, EventArgs e)
{
    Calendar cal=((Calendar)Controls[12]);
    cal.VisibleDate = cal.VisibleDate.AddMonths(1);
    ViewState["visibility"]=true;     
    setLabel();
}

/// <SUMMARY>
/// To Navigate to Next Year
/// </SUMMARY>
private void lblLast_Click(object sender, EventArgs e)
{
    Calendar cal=((Calendar)Controls[12]);
    cal.VisibleDate = cal.VisibleDate.AddYears(1);
    ViewState["visibility"]=true;     
    setLabel();
}

Similarly, we need to navigate to selected month and selected year, when month and year changes.

/// When Month is changed through Dropdown box
/// </SUMMARY>
private void cboyear_SelectedIndexChanged(object sender, EventArgs e)
{
    Calendar cal=((Calendar)Controls[12]);
    DropDownList cboYear=((DropDownList)Controls[7]);
    cal.VisibleDate =Convert.ToDateTime(cal.VisibleDate.ToString("MM") + 
                                  "/15/" + cboYear.SelectedItem.Value );
    ViewState["visibility"]=true; 
    setLabel();
}

/// <SUMMARY>
/// When Year is changed through Dropdown box
/// </SUMMARY>
private void cboMonth_SelectedIndexChanged(object sender, EventArgs e)
{
    Calendar cal=((Calendar)Controls[12]);
    DropDownList cboMonth=((DropDownList)Controls[6]);
    cal.VisibleDate =Convert.ToDateTime(cboMonth.SelectedItem.Value  + 
                           "/15/" + cal.VisibleDate.ToString("yyyy"));
    ViewState["visibility"]=true;         
    setLabel();
}

Calendar control without PostBack

We don't want our calendar to have round trip when user selects a date. As we should assign selected date to assigned control using JavaScript, we need JavaScript code as well as we need to modify calendar control to have days as hyperlink calling that JavaScript.

JavaScript

//Code to emite Javascript that will assign Value to given control
strJavaScript.Remove(0,strJavaScript.Length);
strJavaScript.Append(@"<script language="'JavaScript'">");
strJavaScript.Append(@"function AssignValue(ctrl,val,doc)" + 
      @"{ document.all[ctrl].value=val;document.all[doc]." + 
      @"style.visibility='hidden';}</script>");
Page.RegisterClientScriptBlock("CoolCalJavaScript1",strJavaScript.ToString());

Link Creation

We have to trap DayRender event and modify the contents for the day. First of all, we should remove all existing controls and then add link which will call our JavaScript when day is selected.

/// <SUMMARY>
/// Modify Style of Date Displayed on the Calender to link,
/// also remove autopost back to JavaScript
/// </SUMMARY>
private void cal_DayRender(object sender, DayRenderEventArgs e)
{
    // Clear the link from this day
    e.Cell.Controls.Clear();
    if(!e.Day.IsOtherMonth)   
    {

        // Add the custom link
        System.Web.UI.HtmlControls.HtmlGenericControl Link = 
             new System.Web.UI.HtmlControls.HtmlGenericControl();
        Link.TagName = "a";
        Link.InnerText = e.Day.DayNumberText;

        Link.Attributes.Add("href","javascript:AssignValue('"+ 
                  ControlToAssign +"','"+e.Day.Date.ToString(Format) 
                  +"','"+this.ID+@":Cal')");
        Link.Attributes.Add("style","color:white;TEXT-DECORATION: none");

        // Now add our custom link to the page
        e.Cell.Controls.Add(Link);
    }
    else
    {
        // Add the custom link
        System.Web.UI.HtmlControls.HtmlGenericControl Link = 
              new System.Web.UI.HtmlControls.HtmlGenericControl();
        Link.TagName = "a";
        Link.InnerText = e.Day.DayNumberText;

        Link.Attributes.Add("href","#");
        Link.Attributes.Add("style","color:white;TEXT-DECORATION: none");
    }

    if(e.Day.IsToday)
    {
        e.Cell.BackColor = System.Drawing.Color.LightGray;
    }
}

Final Touch

We need to define properties like BackgroundColor, ForeColor, HeadingColor, HeadingForeColor, VisibleDate, DateFormat, CurrentDateColor, ImgPath (to display initial image), Text (initial text), and the most important AssignToControl. Due to time constraints, I am not able to implement all but I have implemented the important one. You can get this in source code submitted with this article.

History

  • Created on 10th October, 2004.

License

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

Share

About the Author

Gaurang Desai
Architect
United States United States
Currently he is working as Senior Soft. Engineer at Cognizant Technology Solution.He is involved in various project activities like System Architecture, Design, and Development. He is fond of conduction training for various technologies. He has have worked on various language and platforms. He is Microsoft and Oracle Certified professional. He is spending quantity and quality time in .Net world. He had also spoiled his hand with java, too.
If work is not demanding, he spends good time with his wife, Purvi.He
blogs
at WebDevs.com.

Comments and Discussions

 
GeneralMy vote of 5 PinmemberMember 418578210-Jan-11 10:37 
GeneralMy vote of 5 Pinmembersabithpaul6-Jan-11 1:03 
Generalurgent Pinmemberpramod kumar patil15-Apr-08 19:14 
QuestionJavascript error PinmemberParthasarathy Mandayam5-Dec-07 4:34 
GeneralAssigning properties PinmemberParthasarathy Mandayam4-Dec-07 8:44 
QuestionI am getting serious error. Am I alone? PinmemberNovu6-Feb-07 16:42 
AnswerRe: I am getting serious error. Am I alone? Pinmemberfuxiurong_200129-Mar-07 22:59 
GeneralDayPilot - Outlook-like calendar/scheduling control for ASP.NET (open-source) PinmemberDan Letecky28-Jun-06 10:54 
GeneralCool Calendar Control Pinmembersatyen lulla24-Apr-06 23:22 
GeneralViewState Pinmembermitsemaj13-Dec-05 15:39 
GeneralRe: ViewState Pinmembermitsemaj13-Dec-05 15:43 
GeneralControlToAssign does not contains the proper control id PinmemberMehfuz Hossain11-Sep-05 19:14 
GeneralRe: ControlToAssign does not contains the proper control id Pinmembersyao16820-Dec-05 10:20 
GeneralRe: ControlToAssign does not contains the proper control id PinmemberMehfuz Hossain20-Dec-05 17:47 
Generalcan't download the updated code from personal site Pinmembermargiex6-Jul-05 4:42 
GeneralCommCtrl missing PinmemberEzra27-Jun-05 7:36 
GeneralRe: CommCtrl missing PinmemberGaurang Desai27-Jun-05 17:58 
GeneralRe: CommCtrl missing PinmemberEzra28-Jun-05 5:44 
GeneralFile or assembly name CommCtrl, or one of its dependencies, was not found. PinmemberTalis92122-Feb-05 8:50 
GeneralRe: File or assembly name CommCtrl, or one of its dependencies, was not found. PinmemberTalis92122-Feb-05 9:46 
GeneralRe: File or assembly name CommCtrl, or one of its dependencies, was not found. PinmemberRichAlger19-Aug-05 5:56 
Generalmaybe dumb qutione PinsussAnonymous3-Feb-05 8:32 
GeneralLatest Code Base Pinmemberjagdishkab16-Dec-04 5:51 
GeneralA new bug! PinsussDerrick Lin17-Nov-04 22:03 
GeneralRe: A new bug! PinmemberGaurang Desai17-Nov-04 23:46 
GeneralRe: A new bug! PinsussDerrick Lin18-Nov-04 14:28 
GeneralRe: A new bug! PinmemberScottHiett23-Nov-04 4:26 
GeneralRe: A new bug! - SOLVED ! PinmemberVaishali D19-Jun-05 20:17 
GeneralCalendar hides behind drop down PinmemberScottHiett8-Nov-04 8:48 
GeneralRe: Calendar hides behind drop down PinmemberGaurang Desai15-Nov-04 19:49 
GeneralRe: Calendar hides behind drop down PinsussScottHiett16-Nov-04 7:51 
GeneralRe: Calendar hides behind drop down PinmemberGaurang Desai16-Nov-04 17:58 
GeneralRe: Calendar hides behind drop down PinsussDonnadyw55a21-Mar-05 16:37 
GeneralRe: Calendar hides behind drop down Pinmemberkub.net20-Mar-05 8:36 
GeneralBrowse for Image Property Pinmemberpmpjr3-Nov-04 7:36 
GeneralRe: Browse for Image Property PinmemberGaurang Desai3-Nov-04 17:47 
GeneralEscape key to clear pseudo popup Pinmemberpmpjr2-Nov-04 11:23 
GeneralRe: Escape key to clear pseudo popup PinmemberGaurang Desai2-Nov-04 17:45 
GeneralRe: Escape key to clear pseudo popup Pinmemberpmpjr3-Nov-04 5:49 
GeneralRe: Escape key to clear pseudo popup PinmemberGaurang Desai3-Nov-04 17:30 
GeneralRe: Escape key to clear pseudo popup Pinmemberabstar17-Apr-05 16:55 
GeneralJavascript error Pinmemberpmpjr1-Nov-04 4:02 
GeneralRe: Javascript error PinmemberGaurang Desai1-Nov-04 17:58 
GeneralRe: Javascript error PinsussHorst Mayer2-Nov-04 0:24 
GeneralRe: Javascript error PinmemberFrank Petersen2-Nov-04 0:25 
GeneralRe: Javascript error PinmemberGaurang Desai2-Nov-04 1:03 
GeneralRe: Javascript error PinmemberGaurang Desai2-Nov-04 1:05 
GeneralRe: Javascript error Pinmemberpmpjr2-Nov-04 11:02 
Generaldoesn't work on web user controls Pinmemberyuipcheng22-Oct-04 7:22 
GeneralRe: doesn't work on web user controls PinmemberGaurang Desai24-Oct-04 22:25 

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

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

| Advertise | Privacy | Mobile
Web02 | 2.8.140916.1 | Last Updated 12 Oct 2004
Article Copyright 2004 by Gaurang Desai
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid