iCal 风格的月历控件






4.92/5 (12投票s)
一款 iCal 风格的月历控件,具有固定和自定义选择范围、假日高亮显示和可定制外观。
引言
本文描述了一个 iCal 风格的月历控件,具有固定和自定义选择范围、假日高亮显示和可定制外观。以下是截图

背景
在撰写我的毕业设计时,我需要一个可以处理固定选择范围(日、周、月)或自定义范围的日历控件。此外,它必须支持高亮显示假日和可定制外观。我找到了一些商业和免费工具包,但没有一个能满足我的要求,而且大多数看起来相当难看。我想要的是类似于 iCal 导航日历控件的东西。所以我尝试从零开始自己绘制它。
Using the Code
此示例演示了如何实例化控件并使用它。
//
// 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();
}
解决方案
以下是一些实现内部控制逻辑并可能有所帮助的有趣函数。
//
//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;
}
关注点
我发现的许多日历控件只是扩展了标准月历控件的功能,这给控件的设计和外观带来了很多问题。实际上,绘制控件并没有想象中那么难。
一些问题源于不同国家/地区一周的开始日期可能不同,但使用 System.Globalization.CultureInfo
进行一些操作解决了所有问题。
历史
- 首次发布于 2010 年 6 月 4 日