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

Calendar.NET

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (56投票s)

2012年5月5日

CPOL

17分钟阅读

viewsIcon

497951

downloadIcon

44559

适用于.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 - 这是一个布尔属性,用于确定是否自动加载预设的联邦假日到日历中。此属性应尽早设置,并请注意,将此属性设置为truefalse将清除您可能已编程到日历实例中的任何其他事件,因此最好在添加任何事件到日历之前尽早设置此属性。默认情况下,此属性设置为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提供了定义两种不同类型事件的类:HolidayEventCustomEventHolidayEvent是一种描述节假日(如感恩节或圣诞节)的事件。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,当鼠标悬停在事件上时将渲染一个工具提示。

简单总结一下HolidayEventCustomEvent之间的区别,这里是它们的默认属性(当然,任何或所有这些属性都可以被覆盖):

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,并且我们设置了一个名为RehabDaysCustomRecurringFunction。此事件渲染的魔力来自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 -- 首次发布

 

© . All rights reserved.