65.9K
CodeProject 正在变化。 阅读更多。
Home

iCal 风格的月历控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (12投票s)

2010年4月6日

CPOL

1分钟阅读

viewsIcon

40674

downloadIcon

1238

一款 iCal 风格的月历控件,具有固定和自定义选择范围、假日高亮显示和可定制外观。

引言

本文描述了一个 iCal 风格的月历控件,具有固定和自定义选择范围、假日高亮显示和可定制外观。以下是截图

WorkWeek_Calendar_Control

背景

在撰写我的毕业设计时,我需要一个可以处理固定选择范围(日、周、月)或自定义范围的日历控件。此外,它必须支持高亮显示假日和可定制外观。我找到了一些商业和免费工具包,但没有一个能满足我的要求,而且大多数看起来相当难看。我想要的是类似于 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 日
© . All rights reserved.