Click here to Skip to main content
15,868,016 members
Articles / Multimedia / GDI+

A Month Calendar Control in iCal Style

Rate me:
Please Sign up or sign in to vote.
4.92/5 (12 votes)
6 Apr 2010CPOL1 min read 39.4K   1.2K   30   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.

C#
// 
// 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.

C#
//
//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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer UralTEP
Russian Federation Russian Federation
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralGood Job! Pin
Dav26-Apr-10 9:26
Dav26-Apr-10 9:26 

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.