Introduction
As part of a team creating a CRM software package, I am in charge of the user interface portion of the project. A requisite part of all CRM software is an appointment calendar. I initially chose to use the MonthCalendar
control to allow the user to select the date of the appointment. After they create the appointment, I add the new date to the BoldedDates
array of the MonthCalendar
control to designate an appointment on that date. I was frustrated with the lack of customization available to the MonthCalendar
control with regards to appearance. The first meeting with our marketing department (the primary users) yielded requests to make the bolded dates a different color and a more complete month view showing an abbreviation of the appointments for each day. The month view would also need to be printed.
I decided to create my own MonthCalendar
type user control that could be used to select a date and display a larger size of the entire month with appointment abbreviations. This is my first Windows control in .NET, I have seven years Windows experience in VB5 and VB6 but I have mainly spent the last 2 years using C# in ASP.NET applications creating online charts using GDI+.
I broke the development up into two parts.
Part 1. – Create my own MonthCalendar
type control with the same basic functionality as the .NET MonthCalendar
along with the ability to customize all aspects of visual appearance.
Part 2. – Implement the full month view with appointment abbreviations and print functionality.
This article only covers part 1.
Background
The control consists of two Button
s, one Label
, and one PictureBox
. The Button
s are used to move to the next or previous month. The Label
displays the month and year while the PictureBox
displays the actual calendar. The calendar is drawn in the Paint
event of the PictureBox
. The control exposes one additional event, SelectedDateChanged
.
The following properties may be changed:
- Active month background color.
- Inactive month background color.
- Header background color.
- Selected date background color.
- Selected date font color.
- Bolded date font color.
- Grid color.
- Control background color.
- Font used for bolded dates.
- Font used for not bolded dates.
The following properties may be toggled on or off:
- Display previous and next buttons.
- Draw the grid.
- Display month name in active month.
- Abbreviate day name in header.
- Display weekend days darker.
The test application demonstrates changing a few of the properties and displays the SelectedDate
as the title of the form.
Using the code
The entire structure of the code is based on a 7 x 6 grid I use to display the calendar. A 7 x 6 array of integer arrays hold data about each day represented in the grid, one array for the day number and one for the month number. These values determine how each cell of the grid should be drawn. The PictureBox
is divided into an array of rectangles that will be used in the Paint
event.
The control may be used anywhere a standard MonthCalendar
control would be used and it accepts an array of dates to be bolded. It may be sized to fit the space available.
The function that fills the arrays with the appropriate date data was the most interesting part of this phase. See FillDates()
in the source code.
Points of Interest
The control has the ability to display the weekend days slightly darker than the rest of the days of the month. To accomplish this, I create a new color based on the one chosen, and use that color for the brush. In this case, each of the RGB attributes are 80% of the original.
brushActive = new SolidBrush(p_ActiveMonthColor);
ActiveDarker = Color.FromArgb((int)(p_ActiveMonthColor.R*0.8),
(int)(p_ActiveMonthColor.G*0.8),
(int)(p_ActiveMonthColor.B*0.8));
brushActiveDarker = new SolidBrush(ActiveDarker);
The control exposes one additional event, SelectedDateChanged
. This event is fired when the selected date is changed. To do this, I create a class to hold event data. This class must be derived from EventArgs
.
using System;
namespace MPK_Calendar
{
public class SelectedDateChangedEventArgs:EventArgs
{
private DateTime pSelectedDate;
public SelectedDateChangedEventArgs(DateTime dateSelected)
{
pSelectedDate = dateSelected;
}
public DateTime SelectedDate
{
get
{
return pSelectedDate;
}
}
}
}
Declare the delegate of the event:
public delegate void SelectedDateChangedEventHandler(object sender,
SelectedDateChangedEventArgs e);
Provide a public
event member:
#region Custom events
public event SelectedDateChangedEventHandler SelectedDateChanged;
Create a protected
function that raises the event:
protected virtual void
OnSelectedDateChanged(SelectedDateChangedEventArgs eventArgs)
{
if(SelectedDateChanged!=null)
{
SelectedDateChanged(this,eventArgs);
}
}
#endregion Custom events
Finally consume the event in the form of the demo application:
private void mpK_Calendar1_SelectedDateChanged_1(object sender,
MPK_Calendar.SelectedDateChangedEventArgs e)
{
this.Text = e.SelectedDate.ToShortDateString();
}
Everyone knows that public properties can be edited in the properties editor. The two lines above the property definition allowed me to specify a category and a description for use in the property editor:
[Description("Grid color.")]
[Category("MPK_Calendar")]
public Color GridColor
{
get
{
return p_GridColor;
}
set
{
pGridColor=value;
this.picMPK_Cal.Invalidate();
}
}
History
- November 8, 2005 - Fixed a bug that occurs when the month is changed. I also changed the way the date information is stored.
I've been developing software since 1995, using VB5, VB6, ASP, Javascript and most recently C# for ASP.NET and Windows. Current interests include embedded systems for robotics with the BASIC Stamp microcontroller from Parallax and the Brainstem module from Acroname.