SYSK 227: Monthly Calendar control in ASP.NET


Did you ever need a calendar control that allows you to color-code certain days based on your business logic and display details on mouse-over event?  Here is an example of what I’m talking about:



So, perhaps the yellow color means “standard” appointments, and red indicates very important events…  You decide based on your business rules and needs.  This control also raises OnDateClick event so you can, for example, display additional information.  The OnDateClick event is only registered for dates with info, e.g. in the above example the only clickable days are Friday the 3rd and Sunday the 12th.


 


Interested?  Here is the code…  with my standard disclaimer: use at your own risk, has not been rigorously tested, etc.


 


 


1.      Create a class library


2.      Add the following class:


 


using System;


using System.Web;


using System.Web.UI;


using System.Web.UI.WebControls;


 


namespace Web.UI.CustomControls


{


    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal),


        AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)]


    public class MonthlyCalendar : System.Web.UI.WebControls.Table, INamingContainer


    {       


        [Serializable]


        public delegate void DateClickHandler(MonthlyCalendar source, DateTime date);


        private static readonly object EventDateClicked = new object();


 


        public MonthlyCalendar()


        {


            // Set defaults


            base.BorderStyle = BorderStyle.Solid;


            base.CellPadding = 0;


            base.CellSpacing = 0;


            base.BorderColor = System.Drawing.Color.DarkGray;


            base.BorderWidth = 1;                 


        }


 


        public event DateClickHandler OnDateClick


        {


            add { Events.AddHandler(EventDateClicked, value); }


            remove { Events.RemoveHandler(EventDateClicked, value); }


        }


                  


        protected override void CreateChildControls()


        {


            Controls.Clear();


 


            base.CreateChildControls();


           


            // disply title


            DateTime currentDate = new DateTime(Year, (int) Month, 1);


 


            base.Caption = “<p style=\”padding-bottom: 4px\”><b>” + currentDate.ToString(“MMMM yyyy”) + “</b></p>”;


 


 


            base.Rows.Clear();


 


            // Add header


            TableHeaderRow hr = new TableHeaderRow();


            for (short i = 0; i < 7; i++)


            {


                TableHeaderCell c = new TableHeaderCell();


                c.Text = string.Format(“&nbsp;{0}&nbsp;”, ((DayOfWeek)i).ToString().Substring(0, 3));


 


                hr.Cells.Add(c);


            }


            base.Rows.Add(hr);


 


            // Add weeks           


            DateTime endDate = currentDate.AddMonths(1);


            TableRow row = null;


 


            while (currentDate < endDate)


            {


                int dayOfWeek = (int)currentDate.DayOfWeek;


 


                if (row == null || dayOfWeek == (int)DayOfWeek.Sunday)


                {


                    // Create a row


                    row = new TableRow();


                    for (int i = 0; i < 7; i++)


                    {


                        row.Cells.Add(new TableCell());


                    }


 


                    base.Rows.Add(row);


                }


 


                // Add text, back/forecolor


                TableCell currentCell = row.Cells[dayOfWeek];


                currentCell.Text = string.Format(“&nbsp;{0}&nbsp;”, currentDate.Day);


 


                // bool found = false;


                foreach (SeletedPeriod period in Periods)


                {


                    if (currentDate.Day >= period.StartDay && currentDate.Day <= period.EndDay)


                    {


                        currentCell.BackColor = period.BackColor;


                        currentCell.ForeColor = period.ForeColor;


                        currentCell.ToolTip = period.Message;


 


                        currentCell.Attributes[“onclick”] = string.Format(“javascript:{0};”, Page.ClientScript.GetPostBackEventReference(this, string.Format(“SelectDate({0})”, currentDate.Day)));


 


 


                        break;


                    }


                }


 


 


                // Next day


                currentDate = currentDate.AddDays(1);          


            }


        }


 


 


        public int Year


        {


            get { return ViewState[“Year”] == null ? 0 : (int) ViewState[“Year”]; }


            set { ViewState[“Year”] = value; }


        }


 


        public Month Month


        {


            get { return ViewState[“Month”] == null ? Month.Undefined : (Month)ViewState[“Month”]; }


            set { ViewState[“Month”] = value; }           


        }


 


        private System.Collections.Generic.List<SeletedPeriod> Periods


        {


            get { return ViewState[“Periods”] == null ? new System.Collections.Generic.List<SeletedPeriod>() : (System.Collections.Generic.List<SeletedPeriod>)ViewState[“Periods”]; }


            set { ViewState[“Periods”] = value; }           


        }


 


        public void Add(SeletedPeriod period)


        {


            System.Collections.Generic.List<SeletedPeriod> data = Periods;


            data.Add(period);


            Periods = data;  // save in ViewState


        }


 


        public void AddRange(SeletedPeriod[] periods)


        {


            System.Collections.Generic.List<SeletedPeriod> data = Periods;


            data.AddRange(periods);


            Periods = data;  // save in ViewState


        }


 


        public void AddRange(System.Collections.Generic.List<SeletedPeriod> periods)


        {


            System.Collections.Generic.List<SeletedPeriod> data = Periods;


            data.AddRange(periods);


            Periods = data;  // save in ViewState


        }


 


        protected override void RaisePostBackEvent(string eventArgument)


        {


            this.EnsureChildControls();


 


            DateClickHandler handler = (DateClickHandler)Events[EventDateClicked];


            if (handler != null)           


            {


                string eventArg = System.Web.HttpContext.Current.Request[“__EVENTARGUMENT”];


                if (eventArg != null)


                {


                    string searchFor = “SelectDate(“;


 


                    int startPos = eventArg.IndexOf(searchFor);


                    if (startPos != -1)


                    {


                        int endPos = eventArg.IndexOf(‘)’, startPos);


                        if (endPos != -1 && endPos > startPos)


                        {


                            string clickedDate = eventArg.Substring(startPos + searchFor.Length, endPos – startPos – searchFor.Length);


 


                            // Raise event


                            handler(this, new DateTime(Year, (int) Month, int.Parse(clickedDate)));


                        }


                    }


                }


            }           


        }


    }


 


    [Serializable]


    public class SeletedPeriod


    {


        private int _startDay;


        private int _endDay;


        private string _message;


        private System.Drawing.Color _backColor;


        private System.Drawing.Color _foreColor;


 


        public SeletedPeriod(int startDay, int endDay, string message, System.Drawing.Color backColor, System.Drawing.Color foreColor)


        {


            _startDay = startDay;


            _endDay = endDay;


            _message = message;


            _backColor = backColor;


            _foreColor = foreColor;


        }


 


        public int StartDay


        {


            get { return _startDay; }


            set { _startDay = value; }


        }


 


        public int EndDay


        {


            get { return _endDay; }


            set { _endDay = value; }


        }


 


        public string Message


        {


            get { return _message; }


            set { _message = value; }


        }


 


        public System.Drawing.Color BackColor


        {


            get { return _backColor; }


            set { _backColor = value; }


        }


 


        public System.Drawing.Color ForeColor


        {


            get { return _foreColor; }


            set { _foreColor = value; }


        }


    }


 


    public enum Month : short


    {


        Undefined = 0,


        January = 1,


        February = 2,


        March = 3,


        April = 4,


        May = 5,


        June = 6,


        July = 7,


        August = 8,


        September = 9,


        October = 10,


        November = 11,


        December = 12


    }


}


 


3.      On .aspx page, add the following line


<%@ Register Assembly=”Web.UI.CustomControls” Namespace=”Web.UI.CustomControls” TagPrefix=”cc1″ %>


 


and add the actual control:


<cc1:monthlycalendar id=”MonthlyCalendar1″ runat=”server” ></cc1:monthlycalendar>


<asp:Label ID=”SelectedDate” runat=”server”></asp:Label>


 


 


4.      On Page_Load, add your initialization code.  E.g.


if (Page.IsPostBack == false)


{


            MonthlyCalendar1.Month = Web.UI.CustomControls.Month.February;


            MonthlyCalendar1.Year = 2006;


            MonthlyCalendar1.Add(new Web.UI.CustomControls.SeletedPeriod(3, 3, string.Format(“Meeting with Mike @ 11:30 am\r\nHoustons restaurant”), System.Drawing.Color.Yellow, System.Drawing.Color.Black));


            MonthlyCalendar1.Add(new Web.UI.CustomControls.SeletedPeriod(12, 12, string.Format(“Performance review with boss\r\n9:00 am”), System.Drawing.Color.Red, System.Drawing.Color.White));


}


 


MonthlyCalendar1.OnDateClick += new Web.UI.CustomControls.MonthlyCalendar.DateClickHandler(MonthlyCalendar_OnDateClick);


 


 


When a date (appointment) is clicked, it’ll raise an event…  Here is your delegate:


void MonthlyCalendar_OnDateClick(Web.UI.CustomControls.MonthlyCalendar source, DateTime selectedDay)


{


        SelectedDate.Text = selectedDay.ToShortDateString();


}


 


Enjoy!





 

Comments (5)

  1. srinivas says:

    looks good but this one i think works only on .net 2.0 ,so  maybe it would help if you can add the platform it works also in details 🙂

  2. timheuer says:

    why not just use the built-in ASP.NET calendar (which has all the rendering goodness for you and full features) and just attach to its events (or extend it rather than implement your own rendering)

  3. irenake says:

    If you need more functionality, then your suggestion is right on.  However, if you want a control that’s very light, that has just few features described above, then the source code above should get you started.

  4. toji says:

    do u know how can i change the text of DayOfWeek

    i want to cghange sun to bun.. how is that possible ?

  5. ShannanR says:

    Consider doing a modified version of this where you pull the "tooltip" display and populate the days / colors based on info returned from a database table?  Please? 🙂