Calendar.NET
适用于.NET和Winforms应用程序的日/月日历控件,用C#编写
下载二进制文件
下载源代码
引言
最近我需要为我正在编写的应用程序添加一个日历控件。我找不到一个好的,能满足我需求的(其中一个需求是免费或开源的)。所以我决定自己写一个控件。在这篇文章中,我向大家介绍Calendar.NET。Calendar.NET是一个免费的日历控件,它可以渲染成月视图日历或日视图日历。此外,日历中还可以添加事件。这些事件可以是仅发生一次的事件,也可以是周期性事件。日历内置了几种常见的周期性频率,并且还允许您创建自己的频率。最后,日历还预加载了所有联邦假日,您可以选择禁用它们。
使用代码
在深入探讨日历的内部代码工作原理之前,我想先讨论一下如何使用日历。我一直试图遵循KISS(保持简单,傻瓜)原则,并且在此过程中,我认为我让日历控件的使用变得非常简单直观。日历控件需要.NET Framework 3.5或更高版本。开始之前,您只需要在Visual Studio中创建一个新的Windows应用程序,确保目标为.NET 3.5或更高版本。然后添加对日历控件的引用。完成之后,日历控件应该会出现在您的设计器工具箱中。只需将日历控件拖到您的窗体上,您应该就能在窗体上看到一个日历了!日历控件几乎可以渲染成任何大小,并且在需要时还会动态调整大小。
日历控件暴露了许多属性,我现在将逐一详细描述它们。
AllowEditingEvents - 默认情况下,Calendar.NET允许通过鼠标右键单击事件来编辑事件。此属性是一个布尔属性,您可以将其设置为true,以便允许最终用户在运行时编辑事件。将其设置为false将禁用此功能,并阻止最终用户编辑事件。
CalendarDate - 此属性是一个DateTime属性,它告诉日历控件要渲染的日期。如果日历控件正在渲染月视图,则DateTime值的日期部分和时间部分将被忽略。设置此属性将导致日历控件立即更改日期到指定的日期。
CalendarView - 此属性是一个枚举属性,它决定日历应渲染为月视图日历还是日视图日历。要使日历渲染为月视图日历,请将此值设置为CalendarViews.Month。如果您想要日视图,请将此值设置为CalendarViews.Day。
DateHeaderFont - 此属性接受一个Font对象,并使用此字体在右上角渲染CalendarDate。可以使用下面描述的ShowDateInHeader属性禁用显示此标题。
DayOfWeekFont - 此属性也接受一个Font对象,并使用此字体在月视图中渲染星期几(例如,周日、周一、周二、周三、周四、周五、周六)。
DaysFont - 这是另一个Font对象,用于渲染月视图日历中的实际日期。
DayViewTimeFont - 此属性是另一个Font对象,用于渲染日视图日历中的时间。
DimDisabledEvents - 可以禁用Calendar.NET控件中的事件,使其不在日历上渲染。还可以使用下面描述的ShowDisabledEvents属性强制显示这些事件,即使它们被禁用。如果设置显示禁用的事件,则将此属性设置为true将使禁用的事件显示为“变暗”,以给人一种它们被禁用的感觉。将其设置为false将使禁用的事件显示并看起来与正常事件完全一样。
HighlightCurrentDay - 这是一个布尔属性,如果设置为true,将突出显示当前日期(例如今天的日期,而不是CalendarDate属性中设置的当前日期)。默认情况下,此属性为true。如果设置为false,则不会突出显示当前日期。
LoadPresetHolidays - 这是一个布尔属性,用于确定是否自动加载预设的联邦假日到日历中。此属性应尽早设置,并请注意,将此属性设置为true或false将清除您可能已编程到日历实例中的任何其他事件,因此最好在添加任何事件到日历之前尽早设置此属性。默认情况下,此属性设置为true。
ShowArrowControls - 日历可以在日历上方渲染箭头按钮。这些箭头按钮可用于导航到上一个月或下一个月。默认情况下,此属性设置为true。将其设置为false将隐藏这些控件。
ShowDashedBorderOnDisabledEvents - 可以设置通过ShowDisabledEvents属性强制显示的已禁用事件,使其周围显示虚线边框。如果此属性设置为true,则已禁用事件将围绕它们显示虚线边框。
ShowDateInHeader - 通常Calendar.NET会在日历上方显示日历的日期,靠右对齐。通过将此属性设置为false,Calendar.NET将不会渲染此日期。默认情况下,此属性设置为true。
ShowDisabledEvents - 事件可以被设置为禁用,使其不在日历上显示。通过将此属性设置为true,即使禁用的事件也会被渲染。默认情况下,此属性设置为false。
ShowEventTooltips - 当鼠标悬停在事件上时,会显示工具提示。通过将此属性设置为false,将禁用这些工具提示。请注意,此属性会全局关闭所有工具提示。可以为特定或个别事件禁用工具提示。我稍后会向您展示如何做到。
ShowTodayButton - 在导航按钮旁边,通常会渲染一个“今天”按钮。此按钮将立即将用户带到今天的日期。将此属性设置为false将隐藏此按钮。
TodayFont - 这是一个接受Font对象属性,用于渲染“今天”按钮上的文本。
如您所见,Calendar控件可以进行大量自定义。如果您还没有这样做,请将Calendar.NET控件拖到一个空的窗体上,然后添加以下代码。
public Form1()
{
InitializeComponent();
calendar1.CalendarDate = DateTime.Now;
calendar1.CalendarView = CalendarViews.Month;
}
如果您现在运行应用程序,您应该会看到一个月视图日历,以及一个“今天”按钮和导航控件。另外,如果您导航到一个有假日的月份,您应该会在日历上看到该假日。例如,导航到七月,您应该会看到7月4日的一个事件。如果您将鼠标悬停在该事件上,您还可以看到一个工具提示出现。请注意,右键单击假日事件将不起作用,因为默认情况下,您无法编辑假日事件(因为假日事件通常不需要编辑)。
事件
在Calendar.NET中创建事件非常简单。所有事件都只是实现了IEvent
接口的类。Calendar.NET提供了定义两种不同类型事件的类:HolidayEvent
和CustomEvent
。HolidayEvent
是一种描述节假日(如感恩节或圣诞节)的事件。Calendar.NET提供的所有预加载的联邦假日都是此类的实例。CustomEvent
描述了几乎任何自定义事件。您的大部分事件都将是此类实例。当然,您也可以通过简单地实现IEvent
接口来创建自己的事件类。
所有事件,因为它们实现了IEvent
,所以都具有以下属性:
Date - 此属性是事件发生的日期和时间。
Enabled - 此属性决定事件是否启用。如果设置为false,则事件被禁用,它将不会在日历上渲染(除非日历配置为显示禁用的事件)。
EventColor - 此属性是一个Color
对象,它决定用于在日历上渲染事件的背景颜色。
EventFont - 此属性是一个Font
对象,它决定用于渲染事件的字体。
EventLengthInHours - 这是事件的持续时间(以小时为单位)。如果事件持续两个小时,则将其设置为2.0。如果事件持续半小时,则将其设置为0.5。如果事件持续一小时十五分钟,则将其设置为1.25。如果IgnoreTimeComponent
属性设置为true,则将忽略此属性。
EventText - 这是事件的描述。这是将在日历上显示的文本。
EventTextColor - 这是一个Color
属性,它将决定渲染文本的颜色。
IgnoreTimeComponent - 这是一个bool
值,如果设置为true,则将忽略Date属性的时间部分。这对于持续一整天且没有固定时间的事件很有用。
Rank - 此属性是一个整数属性,用于确定在月视图日历上同一天发生的事件的渲染顺序。数字越小,事件的优先级越高。默认情况下,假日事件的秩为1,这意味着它们将在当天首先渲染。自定义事件的秩为2,这意味着它们在假日事件之后渲染。如果两个或多个事件具有相同的秩,则渲染顺序由最早的事件决定,直到最新的。通过为事件设置秩为-1,可以强制事件在所有其他事件之前渲染。
ReadOnlyEvent - 如果将其设置为true,则最终用户无法通过右键单击来修改该事件。默认情况下,此属性设置为false,除非它是HolidayEvent
。
RecurringFrequency - 此属性决定事件应多久渲染一次。Calendar.NET提供了几种内置的重复频率,以及定义自己的选项。此属性可以设置为RecurringFrequencies
枚举中的任何值。有效值为:
- None - 表示此事件是一次性事件,仅应在一天内渲染。
- Daily - 表示此事件是每日事件,应每天渲染。
- EveryWeekday - 表示此事件发生在每个工作日(周一至周五),不包括周末(周六和周日)。
- EveryMonWedFri - 表示此事件将在每个星期一、星期三和星期五渲染。
- EveryTueThurs - 表示此事件将在每个星期二和星期四渲染。
- Weekly - 表示此事件每周渲染一次,在指定日期所在的那一周的某一天。
- Monthly - 表示此事件每月渲染一次,在日历日期指定的某一天。
- Yearly - 表示此事件每年渲染一次,在日历日期指定的日期和月份。
- EveryWeekend - 表示事件将在每个星期六和星期日渲染。
- Custom - 表示该事件具有唯一的重复频率。我稍后将展示一个如何实现此功能的示例。
CustomRecurringFunction - 这是一个属性,它接受一个类型为CustomRecurringFrequenciesHandler
的委托函数。此函数将接收事件和渲染日期,并应返回一个布尔值,指示该事件是否应在此日期渲染。稍后将提供此功能的示例。除非RecurringFrequency
属性设置为Custom
,否则将忽略此属性。
ThisDayForwardOnly - 如果此属性设置为true,则事件仅在日期晚于或等于日历日期时渲染。如果设置为false,那么如果事件是重复的,它也会显示在日历的过去日期中。
TooltipEnabled - 如果设置为true,当鼠标悬停在事件上时将渲染一个工具提示。
简单总结一下HolidayEvent
和CustomEvent
之间的区别,这里是它们的默认属性(当然,任何或所有这些属性都可以被覆盖):
HolidayEvent
EventColor
将是浅蓝色。EventFont
将是Arial 8pt Bold。EventTextColor
是白色。EventLengthInHours
设置为24(因为假日通常是全天事件)。ReadOnlyEvent
设置为true,这意味着您不能编辑它们。IgnoreTimeComponent
设置为true,同样因为它们是全天事件。TooltipEnabled
设置为true,这意味着悬停时会显示工具提示。ThisDayForwardOnly
设置为false,因为假日不仅现在发生,去年也发生。Rank
设置为1,这意味着它们在日历上首先渲染,在CustomEvents
之前。
CustomEvent
EventColor
将是红色。EventFont
将是Arial 8pt Bold。EventTextColor
是白色。EventLengthInHours
设置为1小时。ReadOnlyEvent
设置为false,这意味着最终用户可以编辑该事件。IgnoreTimeComponent
设置为false 。ThisDayForwardOnly
设置为true,因为大多数事件不需要在过去重复。Rank
设置为2,这意味着它们在HolidayEvents
之后渲染。
创建自定义假日事件
创建假日事件非常简单。假设我们想创建一个每年2月2日发生的土拨鼠日的日历事件。在您之前在Form1
的构造函数中添加的代码之后,添加此代码:
var groundhogEvent = new HolidayEvent
{
Date = new DateTime(2012, 2, 2),
EventText = "Groundhog Day",
RecurringFrequency = RecurringFrequencies.Yearly
};
calendar1.AddEvent(groundhogEvent);
这段代码创建了一个新的HolidayEvent
。它将日期设置为2012年2月2日。由于这是一个每年都会重复的事件,年份无关紧要。它每年都会渲染。我们将文本设置为“土拨鼠日”,然后将RecurringFrequency
设置为yearly。最后,通过调用AddEvent
方法将事件添加到日历中。AddEvent
方法接受一个IEvent
参数并将IEvent
添加到日历中。如果您现在运行程序并导航到任何年份的二月,您应该会在日历上看到土拨鼠日事件。恭喜!您刚刚添加了第一个事件!您可以随意修改该事件,更改一些属性,然后查看结果。
创建自定义事件
创建自定义事件与创建假日事件一样简单。在此示例中,我们将创建一个事件来提醒我们每周一、周三和周五进行锻炼。在您的土拨鼠日事件之后,将此代码添加到构造函数中:
var exerciseEvent = new CustomEvent
{
Date = DateTime.Now,
RecurringFrequency = RecurringFrequencies.EveryMonWedFri,
EventText = "Time for Exercise!"
};
calendar1.AddEvent(exerciseEvent);
此代码创建了一个CustomEvent
对象,将日期设置为今天,将RecurringFrequency
设置为EveryMonWedFri
,最后将文本设置为“该锻炼了!”。如果您现在运行程序,您会看到该事件现在每周一、周三和周五出现。另外需要注意的一点是,这与我们的HolidayEvent
不同,默认情况下,ThisDayForwardOnly
属性设置为true。这意味着该事件在今天(DateTime.Now
之前)之前不会显示。如果您将此属性更改为false然后重新运行程序,您会看到我们的事件将每周一、周三和周五出现,即使我们回到一年前。
我还有一件事想向您展示。如果您右键单击该事件,您会看到一个名为“属性”的菜单。如果您单击它,将弹出一个对话框,允许您实时修改事件。此功能可以通过将事件本身的ReadOnlyEvent
属性设置为true或将日历控件中的AllowEditingEvents
属性设置为false来禁用。
创建具有自定义重复频率的事件
Calendar.NET的一个很酷之处在于,如果没有任何预打包的重复频率能满足您的需求,您可以创建自己的。为了演示这一点,我们将创建一个仅在每周一和周五发生的事件。此特定事件仅需要在6月之前发生。它不应发生在2012年6月之后。要做到这一点,请在您的锻炼事件之后,在构造函数中添加此代码:
var rehabEvent = new CustomEvent
{
Date = DateTime.Now,
RecurringFrequency = RecurringFrequencies.Custom,
EventText = "Rehab Therapy",
Rank = 3,
CustomRecurringFunction = RehabDays
};
calendar1.AddEvent(rehabEvent);
此事件的设置几乎与我们的自定义锻炼事件相同。主要区别在于,我们将RecurringFrequency
属性设置为Custom
,并且我们设置了一个名为RehabDays
的CustomRecurringFunction
。此事件渲染的魔力来自RehabDays函数。将此函数添加到我们的Form1
类中:
[CustomRecurringFunction("RehabDates", "Calculates which days I should be getting rehab therapy")]
private bool RehabDays(IEvent evnt, DateTime day)
{
if (day.DayOfWeek == DayOfWeek.Monday || day.DayOfWeek == DayOfWeek.Friday)
{
if (day.Ticks >= (new DateTime(2012, 7, 1)).Ticks)
return false;
return true;
}
return false;
}
设置这样的函数很容易。首先,我在函数上添加了一个名为CustomRecurringFunction
的属性标签。此属性不是必需的,实际上也没有任何作用,但我在该控件的未来版本中有计划使用它,所以我建议添加它。自定义重复函数总是接收两个参数并返回一个bool。所有自定义重复函数都必须具有此签名。它的工作原理是,当Calendar.NET开始渲染日历并检测到一个具有自定义重复频率的事件时,Calendar.NET基本上会调用您的自定义函数,说“我即将在此日期渲染日历。这个事件是否应该被渲染?”。然后由您的函数决定它是否应该被渲染,如果应该则返回true,如果不应该则返回false。IEvent
参数是要渲染的事件。DateTime
参数是要渲染的日期。在此函数中,我们首先决定是星期一还是星期五。如果是,然后我们决定日期是否是2012年7月1日或之后。如果是,我们返回false,因为我们不希望在7月1日或之后渲染此事件。如果不是,我们返回true,表示应该渲染。希望这一切都能讲得通:)
如果您现在运行程序,您将看到我们的新事件,并且它确实会每周一和周五渲染。此外,如果您导航到六月之后,您将看到日历上不再有该事件。
使日历变为日视图
到目前为止,我们所做的一切都展示了Calendar.NET作为月视图日历的强大功能。Calendar.NET还可以渲染为日视图日历,逐小时显示事件。要使日历渲染为日视图日历,您只需更改构造函数中读取calendar1.CalendarView = CalendarViews.Month;
的行,并将其更改为calendar1.CalendarView = CalendarViews.Day;
。仅此而已。现在我们需要创建一个事件来演示。在构造函数中,在我们的Rehab事件之后,添加此代码:
var ce2 = new CustomEvent { IgnoreTimeComponent = false, EventText = "Dinner", Date = new DateTime(2012, 5, 15, 18, 0, 0), EventLengthInHours = 2f, RecurringFrequency = RecurringFrequencies.None, EventFont = new Font("Verdana", 12, FontStyle.Regular), Enabled = true, EventColor = Color.FromArgb(120, 255, 120), EventTextColor = Color.Black, ThisDayForwardOnly=false }; calendar1.AddEvent(ce2);
这段代码将创建一个新的自定义事件,提醒我们在2012年5月15日晚上6点吃晚餐。我们不希望忽略此事件的时间部分,因为此事件发生在特定时间。晚餐将是两个小时的事件,并且不是重复事件。我们将此事件的颜色更改为绿色,以便事件与其他所有事件区分开来。如果您现在运行应用程序,您会发现日历看起来与以前大不相同。日历现在按特定日期显示事件。每天显示24小时,从午夜开始到当晚11:59结束。如果您看不到日历上的所有日期,请用鼠标左键单击日历上的任何位置,然后向上或向下拖动以滚动日历。如果您导航到5月15日并向下滚动到下午6点,您应该会看到我们的晚餐事件。另外请注意,该事件占用了我们两个小时的时间。该事件的绿色块从下午6点线开始,到下午8点线结束。
结论
我希望您喜欢这个控件,并希望收到有关它的评论。请告诉我任何错误或问题,我将在下一个版本中修复它们。
历史
版本1.0 -- 首次发布