Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Month Calendar Control in iCal Style

0.00/5 (No votes)
6 Apr 2010 1  
A month calendar control in iCal style with fixed and custom selection ranges, holidays highlight and customizable appearance

Introduction

This article describes a month calendar control in iCal style with fixed and custom selection ranges, holidays highlight and customizable appearance. Here is a screenshot:

WorkWeek_Calendar_Control

Background

Writing my diploma project, I needed a calendar control that can work with fixed selection ranges (day, week, month) or custom ranges. Besides it must support highlighted holidays and customizable appearance. I found some commercial and free toolkits, but none of them met my requirements and majority of them look rather ugly. What I wanted was something like iCal navigation calendar control. So I tried to draw it myself from nothing.

Using the Code

This sample shows how to instantiate a control and use it.

// 
// ww_monthcal1
// 
this.ww_monthcal1.BackCalDates = System.Drawing.Color.White;
this.ww_monthcal1.BackSelDates = System.Drawing.Color.Gray;
this.ww_monthcal1.Dock = System.Windows.Forms.DockStyle.Fill;
this.ww_monthcal1.Holid = System.Drawing.Color.Red;
this.ww_monthcal1.Location = new System.Drawing.Point(0, 0);
this.ww_monthcal1.MinimumSize = new System.Drawing.Size(124, 106);
this.ww_monthcal1.Name = "ww_monthcal1";
this.ww_monthcal1.SelectionMode = WorkWeek.ww_monthcal.SMode.Day;
this.ww_monthcal1.Size = new System.Drawing.Size(257, 337);
this.ww_monthcal1.Start = new System.DateTime(2010, 3, 22, 0, 0, 0, 0);
this.ww_monthcal1.TabIndex = 0;
this.ww_monthcal1.Text = "ww_monthcal1";
this.ww_monthcal1.SELCHANGE += new WorkWeek.ww_monthcal.SELECTION_CHANGE 
				(this.ww_monthcal1_SELCHANGE);

// 
// Form1
// 

private void ww_monthcal1_SELCHANGE(DateTime Start, DateTime End)
{
    Text=Start.ToString()+" - "+End.ToString();
}

Solution

Here are some interesting functions that realize inner control logic and can be helpful.

//
//get local day name from index
//
private string localdaynameFROMindex(int index)
{
    CultureInfo local = CultureInfo.CurrentCulture;
    int daynn = (int)(System.Globalization.CultureInfo.
	CurrentCulture.DateTimeFormat.FirstDayOfWeek); //first day of week
    int actualdayn = daynn + index;
    if (actualdayn == 7) actualdayn = 0;
    return local.DateTimeFormat.GetAbbreviatedDayName((DayOfWeek)actualdayn);
}

//
//this function returns rectangle of date
//
private Rectangle DATERECT(DateTime dt)
{
    DateTime monthst = new DateTime(dt.Year, dt.Month, 1);
    int x = 0;
    int y = 0;
    int dy = this.Font.Height;
    int dx = this.Width / 7;
    int daystostartday = 0;
    int daynv = (int)monthst.DayOfWeek; //first day of month
    int daynn = (int)(System.Globalization.CultureInfo.
	CurrentCulture.DateTimeFormat.FirstDayOfWeek); //first day of week
    if (daynn <= daynv)
        daystostartday = daynv - daynn;
    else
        daystostartday = 7 - daynn - daynv;
        
    x = (int)((int)(((dt - monthst).TotalDays + daystostartday) % 7) * dx) + 1;
    y = (int)((int)(((dt - monthst).TotalDays + daystostartday) / 7) * dy) + 2 * dy;
    
    return new Rectangle(x, y, dx, dy);
}

//
//convert coordinate on control to date
//
private DateTime XYtoDATE(int X, int Y, int list)
{
    DateTime dt = new DateTime(mStart.Year, mStart.Month, 1).AddMonths(list);
    int daystostartday = 0;
    int daynv = (int)dt.DayOfWeek; //first day of month
    int daynn = (int)(System.Globalization.CultureInfo.CurrentCulture.
		DateTimeFormat.FirstDayOfWeek); //first day of week
    if (daynn <= daynv)
        daystostartday = daynv - daynn;
    else
        daystostartday = 7 - daynn - daynv;
    int dy = this.Font.Height;
    int dx = this.Width / 7;
    int XYcolumn = (int)(X / dx);
    int XYstring = (int)((Y - 2 * dy) / dy);
    int adddays = 7 * (XYstring) + XYcolumn - daystostartday;
    if (adddays < 0)
        adddays = 0;
    if (adddays >= DateTime.DaysInMonth(dt.Year, dt.Month))
        adddays = DateTime.DaysInMonth(dt.Year, dt.Month) - 1;
    dt = dt.AddDays(adddays);
    return dt;
} 

Points of Interest

Lots of calendar controls I found just extend the functionality of standard month calendar control that brings lots of problems with design and appearance of control. Drawing a control actually wasn’t as hard as it seemed before.

Some problems come from the fact that week can start with different days in different countries, but doing some manipulations with System.Globalization.CultureInfo solved all problems.

History

  • First version published on 6/04/2010

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here