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

A Month Calendar Control in iCal Style

, 6 Apr 2010
Rate this:
Please Sign up or sign in to vote.
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Evgeny Bannikov
Engineer UralTEP
Russian Federation Russian Federation
No Biography provided

Comments and Discussions

 
GeneralGood Job! PinmemberDavide Vitelaru6-Apr-10 9:26 

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
Web01 | 2.8.140905.1 | Last Updated 6 Apr 2010
Article Copyright 2010 by Evgeny Bannikov
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid