Customizable MonthCalendar Type Control: Part I

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 added 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 the 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+.  

Calendar.jpg

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 the visual appearance.

Part 2. - Implement the full month view with appointment abbreviations and print functionality.

This article only covers part 1.

Background (optional)

The control consists of two buttons, one label, and one picturebox. The buttons 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
{
///

///
Event argument class.
///

public class
SelectedDateChangedEventArgs:EventArgs
{
private
DateTime pSelectedDate;
///
<summary>
///
Constructor
///
</summary>
///
<param name="dateSelected">Date
</param>
public
SelectedDateChangedEventArgs(DateTime dateSelected)
{
pSelectedDate = dateSelected;
}
///
<summary>
///
The selected date.
///
</summary>
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
///

///
Event handler definition
///

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

Keep a running update of any changes or improvements you've made here.


Similar Articles