Windows Develop Bookmark and Share   
 index > Windows Forms Designer > Extended monthCalendar
 

Extended monthCalendar

Hi everybody, I have a little problem.
I found this example of extended monthCalendar, which has some background of day painted another color.
On system winXP goes well, but on system Vista particular days have wrong position.
Does anyone know, how can I resolve this problem?
Thanks Ondrej


Code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Threading;

namespace Calendar
{
public partial class RegnumCalendar : MonthCalendar
{
private ArrayList warningDates = new ArrayList();

public enum SelectionType
{
Dovolena = 1,
Vikend = 2
}

public RegnumCalendar()
{
//SetStyle(ControlStyles.UserPaint,true);
InitializeComponent();
warningDates.Add(new DateTime(2007, 12, 1));
warningDates.Add(new DateTime(2007, 12, 20));
warningDates.Add(new DateTime(2007, 12, 31));
}

public void addNewDate(ArrayList list)
{
this.warningDates.AddRange(list);
Graphics graphics = Graphics.FromHwnd(this.Handle);
PaintEventArgs pe = new PaintEventArgs(graphics, new Rectangle(0, 0, this.Width, this.Height));
OnPaint(pe);
}

// Override WndProc and force a call to OnPaint when we get a WM_PAINT
protected static int WM_PAINT = 0x000F;
protected static int WM_RBUTTONUP = 0x0205;

protected override void WndProc(ref System.Windows.Forms.Message m)
{
if (m.Msg == WM_RBUTTONUP)
{
//showContextMenu();
m.Result = IntPtr.Zero;
//return;
}
base.WndProc(ref m);
if (m.Msg == WM_PAINT)
{
Graphics graphics = Graphics.FromHwnd(this.Handle);
PaintEventArgs pe = new PaintEventArgs(graphics, new Rectangle(0, 0, this.Width, this.Height));
OnPaint(pe);
}
}

protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);

Graphics graphics = e.Graphics;

int dayBoxWidth = 0;
int dayBoxHeight = 0;
float dayBoxWidthF = 0;
float dayBoxHeightF = 0;
int firstWeekPosition = 0;
int lastWeekPosition = Height;

if (warningDates.Count > 0)
{
SelectionRange calendarRange = GetDisplayRange(false);

// Create a list of those dates that actually should be marked as warnings.
ArrayList visibleWarningDates = new ArrayList();
foreach (DateTime date in warningDates)
{
if (date >= calendarRange.Start && date <= calendarRange.End)
{
visibleWarningDates.Add(date);
}
}
if (visibleWarningDates.Count > 0)
{
while ((HitTest(25, firstWeekPosition).HitArea != HitArea.PrevMonthDate && HitTest(25, firstWeekPosition).HitArea != HitArea.Date) && firstWeekPosition < Height)
{
firstWeekPosition++;
}

while ((HitTest(25, lastWeekPosition).HitArea != HitArea.NextMonthDate && HitTest(25, lastWeekPosition).HitArea != HitArea.Date) && lastWeekPosition >= 0)
{
lastWeekPosition--;
}

if (firstWeekPosition > 0 && lastWeekPosition > 0)
{
dayBoxWidth = Width / (ShowWeekNumbers ? 8 : 7);
dayBoxWidthF = Width / (ShowWeekNumbers ? 8.0f : 7.0f);
dayBoxHeight = (int)(((float)(lastWeekPosition - firstWeekPosition)) / 6.0f);
dayBoxHeightF = ((float)(lastWeekPosition - firstWeekPosition)) / 6.0f;
//dayBoxHeightF = Height / 9;
using (Brush warningBrush = new SolidBrush(Color.FromArgb(255, Color.Red)))//.FromArgb(255, 240, 240))))
{
foreach (DateTime visDate in visibleWarningDates)
{
int row = 0;
int col = 0;

TimeSpan span = visDate.Subtract(calendarRange.Start);
row = span.Days / 7;
col = span.Days % 7;

Rectangle fillRect = new Rectangle((col + (ShowWeekNumbers ? 1 : 0)) * dayBoxWidth + 2, firstWeekPosition + row * dayBoxHeight + 2, dayBoxWidth -2, dayBoxHeight -2);
Rectangle fillRectF = new Rectangle((int)Math.Round((col + (ShowWeekNumbers ? 1 : 0)) * dayBoxWidthF,0)+2, (int)(firstWeekPosition + row * dayBoxHeightF)+1, (int)dayBoxWidthF-2, (int)dayBoxHeightF+1);
graphics.FillRectangle(warningBrush, fillRect);
//graphics.FillRectangle(warningBrush, ((col + (ShowWeekNumbers ? 1 : 0)) * dayBoxWidthF) + 2, (firstWeekPosition + row * dayBoxHeightF) + 1, dayBoxWidthF - 2, dayBoxHeightF + 1);

// Check if the date is in the bolded dates array
bool makeDateBolded = false;
foreach (DateTime boldDate in BoldedDates)
{
if (boldDate == visDate)
{
makeDateBolded = true;
}
}

using (Font textFont = new Font(Font, (makeDateBolded ? FontStyle.Bold : FontStyle.Regular)))
{
TextRenderer.DrawText(graphics, visDate.Day.ToString(), textFont, fillRect, Color.FromArgb(255, 128, 0, 0), TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
}
}
}
}
}
}
}
}
}

Zenisek Ondrej  Wednesday, January 02, 2008 9:23 AM
I tried comment this //Application.EnableVisualStyles(); and after that it is ok, only monthcalendar has other look.
Zenisek Ondrej  Wednesday, January 02, 2008 11:55 AM
I tried comment this //Application.EnableVisualStyles(); and after that it is ok, only monthcalendar has other look.
Zenisek Ondrej  Wednesday, January 02, 2008 11:55 AM
Hi all,

This is my first post on MSDN! I was looking for a MonthCalendar able to highlight several important days... The BoldedDates property was good for this but not enough visible for the user!

I found this code and I notice it was just working in single month view. When the MonthCalendar.Dock property is set to "Fill" the code doesn't work anymore or the behavior was unpredictable when several months were displayed... The same issue arrives when the font size is modified.

I did not want to use an Open Source component as we can see when we search "Extended month calendar" trough the web... Just want to upgrade the existing one and i found this code and modified it.

Feel free to use and abuse it!

public partial class ExtendedCalendar : MonthCalendar
{
//Default Colors for the hilghlighted days
private Color highLightBackColor = Color.Red;
private Color highLightForeColor = Color.Black;

public ExtendedCalendar()
{
InitializeComponent();
}

//Property for the back color of high light days
public Color HighLightBackColor
{
get { return highLightBackColor; }
set { highLightBackColor = value; }
}

//Property for the fore color of high light days
public Color HighLightForeColor
{
get { return highLightForeColor; }
set { highLightForeColor = value; }
}

// Override WndProc and force a call to OnPaint when we get a WM_PAINT
protected static int WM_PAINT = 0x000F;
protected static int WM_RBUTTONUP = 0x0205;

protected override void OnResize(EventArgs e)
{
base.OnResize(e);
Refresh();
Graphics graphics = Graphics.FromHwnd(this.Handle);
PaintEventArgs pe = new PaintEventArgs(graphics, new Rectangle(0, 0, this.Width, this.Height));
OnPaint(pe);
}

protected override void WndProc(ref System.Windows.Forms.Message m)
{
if (m.Msg == WM_RBUTTONUP)
{
//showContextMenu();
m.Result = IntPtr.Zero;
//return;
}
base.WndProc(ref m);
if (m.Msg == WM_PAINT)
{
Graphics graphics = Graphics.FromHwnd(this.Handle);
PaintEventArgs pe = new PaintEventArgs(graphics, new Rectangle(0, 0, this.Width, this.Height));
OnPaint(pe);
}
}

protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);

Graphics graphics = e.Graphics;

int dayBoxWidth = 0;
int dayBoxHeight = 0;
int xPosition = 0;
int yPosition = 0;

if (BoldedDates.Count() > 0)
{
SelectionRange calendarRange = GetDisplayRange(true);
// Create a list of those dates that actually should be marked as warnings.
ArrayList visibleWarningDates = new ArrayList();
foreach (DateTime date in BoldedDates)
{
if (date >= calendarRange.Start && date <= calendarRange.End)
{
visibleWarningDates.Add(date);
}
}
if (visibleWarningDates.Count > 0)
{
//Get the font heigth to be font size independant
int fHeight = this.Font.Height;


//Coordinate to be sure to hit a calendar vertically and horizontally
//The middle of the component is not ok for the 2*2 month dispositions
//that's why I substract a quarter of one calendar size!
int hitHeigth = (Height / 2) - (SingleMonthSize.Height / 4);
int hitWidth = (Width / 2) - (SingleMonthSize.Width / 4);

int halfWidth = Width / 2;
int halfHeight = Height / 2;

//Searching the x and y distance between component border and the calendar displayed!
//Sometimes after resizing the HitTest fail to return real values,
//stopping at the half height & width to avoid no end loops
while (HitTest(hitWidth, yPosition).HitArea == HitArea.Nowhere && yPosition < halfHeight)
yPosition++;

while (HitTest(xPosition, hitHeigth).HitArea == HitArea.Nowhere && xPosition < halfWidth)
xPosition++;

//Calculate the total of month displayed
int totalMonths = ((calendarRange.End.Year - calendarRange.Start.Year) * 12) + calendarRange.End.Month + 1 - calendarRange.Start.Month;


int calMonthWidth = 1;

//Calculate the real CalendarDimensions!
if (CalendarDimensions.Width * CalendarDimensions.Height > 1)
{
//The group of month is centered vertically and horizontally
//That's why i choose to multiply the yPosition by 2
//If the font Heigth is not added on one hand an substracted on the other hand, the calcul can be wrong!
int realHeigth = CalendarDimensions.Height - ((yPosition * 2 + fHeight) / (SingleMonthSize.Height - fHeight));
calMonthWidth = totalMonths / (realHeigth == 0 ? 1 : realHeigth);
//Be sure calMonthWidth is not equal to 0 to avoid division by 0 exception!
calMonthWidth = (calMonthWidth == 0 ? 1 : calMonthWidth);
}


//Setting proportions of a dayBox
//Fotunately it's proportionnal to the SingleMonthSize and the font Height
dayBoxWidth = this.SingleMonthSize.Width / (ShowWeekNumbers ? 8 : 7);
dayBoxHeight = (int)((this.SingleMonthSize.Height - fHeight) / 9);

using (Brush warningBrush = new SolidBrush(Color.FromArgb(255, highLightBackColor)))
{
foreach (DateTime visDate in visibleWarningDates)
{
int row = 0;
int col = 0;

//Calculate the absolute position of the month containing the visDate
int posMonth = ((visDate.Year - calendarRange.Start.Year) * 12) + visDate.Month - calendarRange.Start.Month;

//Dividing it into col and row position
int monthRow = posMonth / calMonthWidth;
int monthCol = posMonth % calMonthWidth;

//Calculating the difference between the date and the first date in the month
DateTime firsDateOfMonth = new DateTime(visDate.Year, visDate.Month, 1);

//Looking for the firs day in the week for the current culture
DayOfWeek firstDay = Application.CurrentCulture.DateTimeFormat.FirstDayOfWeek;

//Calculating the position of the date in the month
TimeSpan span = visDate.Subtract(firsDateOfMonth.AddDays(-((int)firsDateOfMonth.DayOfWeek) + (int)firstDay));

//DayOfWeek enum is starting at Sunday ( = 0) solving the problem for other cultures
if ((int)firstDay != 0 && (int)firsDateOfMonth.DayOfWeek == 0)
span = span.Add(new TimeSpan(7, 0, 0, 0));

//Calculating the row and the column in the month
row = span.Days / 7;
col = span.Days % 7;

//Creating the rectangle to draw the highlight days
//xPosition and yPosition represent the top left corner of the group of months
//SingleMonthSize with monthRow and monthCol let me aim the top left corner of the particular month of the visDate
//col and row are used to calculate the final position in the month
//dayBoxWidth & dayBoxHeight define the size of the rectangle
Rectangle fillRect = new Rectangle(
xPosition + (monthCol * (SingleMonthSize.Width + 6)) + ((col + (ShowWeekNumbers ? 1 : 0)) * dayBoxWidth + 1),
yPosition + (monthRow * (SingleMonthSize.Height - (fHeight - 2))) + (row * dayBoxHeight + ((SingleMonthSize.Height - fHeight) / 3)),
dayBoxWidth - 2,
dayBoxHeight - 2
);

graphics.FillRectangle(warningBrush, fillRect);

//Uncomment following code if you are not using BoldedDates and switch the "using"

// Check if the date is in the bolded dates array
//bool makeDateBolded = false;
//if (BoldedDates.Contains(visDate))
// makeDateBolded = true;
//using (Font textFont = new Font(Font, (makeDateBolded == true ? FontStyle.Bold: FontStyle.Regular)))

using (Font textFont = new Font(Font, FontStyle.Bold))
{
TextRenderer.DrawText(graphics, visDate.Day.ToString(), textFont, fillRect, highLightForeColor, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
}
}
}
}
}
}
}
Mad Piou  Monday, September 14, 2009 12:33 PM

You can use google to search for other answers

Custom Search

More Threads

• vb.net 2005 shutdown error when adding default icon to property page
• Designer error
• Custom Designer Problem - Customise the resize handle arround a user control
• Autocomplete on axWebbrowser
• DataGridView column separator can't move beyond window limits.
• how to use "SocketType.Rdm" to create a socket?
• VS2005 Designer fails on inherited user control
• Error in Updating database table using OdbcDataAdapter.Update() method
• How to show Multiple check boxes in TreeView Control.
• Windows XP Buttons Style