WinForm之MonthCalendar 控件

在 WinForm 中,MonthCalendar是一个用于直观展示日历并支持日期选择的控件,与DateTimePicker相比,它更适合选择日期范围(如入住 / 离店时间、假期起止日期)或需要同时查看多个月份的场景。它能显示一个或多个月份的完整日历网格,支持单个日期、连续多日或不连续日期的选择。

一、控件简介

MonthCalendar的核心特点:

  • 可显示 1 个或多个月份(通过CalendarDimensions设置行列数);

  • 支持选择单个日期、连续日期范围或多个不连续日期;

  • 可高亮显示特定日期(如节假日、截止日);

  • 提供直观的翻页按钮(切换月份 / 年份)和今天日期快速定位。

二、核心属性(表格整理)

属性名称类型说明
SelectionStartDateTime获取或设置选择范围的起始日期(连续选择时有效)
SelectionEndDateTime获取或设置选择范围的结束日期(连续选择时有效)
SelectedDatesSelectedDatesCollection包含所有选中的日期(支持不连续选择,通过Add/Remove方法操作)
MaxSelectionCountint设置最大可选择的天数(默认 7 天,0 表示无限制,连续选择时生效)
MinDateDateTime可选择的最小日期(早于该日期的日期不可选)
MaxDateDateTime可选择的最大日期(晚于该日期的日期不可选)
CalendarDimensionsSize设置显示的月份行数和列数(如new Size(2, 2)表示 2 行 2 列共 4 个月份)
ShowTodaybool是否在底部显示 “今天” 日期(默认true,点击可快速跳转到今天)
ShowTodayCirclebool是否用圆圈标记今天日期(默认true
ShowWeekNumbersbool是否在左侧显示周数(默认false
FirstDayOfWeekDayOfWeek设置每周的第一天(如DayOfWeek.Monday表示周一为一周起点)

三、核心事件

事件名称说明
DateSelected当用户选择的日期范围或单个日期发生变化时触发(如拖动选择、点击新日期)
DateChanged当控件显示的月份范围发生变化时触发(如点击翻页按钮切换月份)

四、基础用法示例(选择日期范围)

场景:酒店预订时选择入住和离店日期,限制最多选择 30 天,且只能选择未来日期。

1. 界面设计

在窗体中添加:

  • MonthCalendar控件(命名为monthCalendar1);

  • Label控件(命名为lblResult,用于显示选择结果)。

2. 代码实现
using System;
using System.Windows.Forms;
​
namespace MonthCalendarDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            // 初始化日历控件
            InitCalendar();
        }
​
        private void InitCalendar()
        {
            // 限制选择范围:只能选择今天及以后的日期
            monthCalendar1.MinDate = DateTime.Today;
            // 最大选择30天(连续选择时生效)
            monthCalendar1.MaxSelectionCount = 30;
            // 显示2行1列共2个月份
            monthCalendar1.CalendarDimensions = new System.Drawing.Size(1, 2);
            // 显示周数
            monthCalendar1.ShowWeekNumbers = true;
            // 默认选中今天
            monthCalendar1.SetDate(DateTime.Today);
        }
​
        // 日期选择变化时触发
        private void monthCalendar1_DateSelected(object sender, DateRangeEventArgs e)
        {
            // 显示选择的起始和结束日期
            if (e.Start == e.End)
            {
                // 只选择了单个日期
                lblResult.Text = $"选中日期:{e.Start:yyyy年MM月dd日}";
            }
            else
            {
                // 选择了日期范围
                int days = (e.End - e.Start).Days + 1; // 计算天数(包含首尾)
                lblResult.Text = $"入住:{e.Start:yyyy年MM月dd日}  离店:{e.End:yyyy年MM月dd日}  共{days}天";
            }
        }
    }
}

五、进阶用法与技巧

1. 高亮显示特定日期(如节假日)

通过AddBoldedDate方法可将指定日期加粗显示,适合标记重要日期:

// 高亮显示国庆节和元旦
private void HighlightHolidays()
{
    // 添加需要高亮的日期
    monthCalendar1.AddBoldedDate(new DateTime(2024, 10, 1));
    monthCalendar1.AddBoldedDate(new DateTime(2025, 1, 1));
    // 应用更改(必须调用此方法才会生效)
    monthCalendar1.UpdateBoldedDates();
}
​
// 清除所有高亮日期
private void ClearHighlightedDates()
{
    monthCalendar1.RemoveAllBoldedDates();
    monthCalendar1.UpdateBoldedDates();
}
2. 选择多个不连续日期

SelectedDates属性支持添加不连续日期(需先取消连续选择限制):

// 允许选择不连续日期(设置MaxSelectionCount为0表示无限制)
monthCalendar1.MaxSelectionCount = 0;
​
// 代码添加多个不连续日期
private void AddDiscontinuousDates()
{
    monthCalendar1.SelectedDates.Clear(); // 清空现有选择
    monthCalendar1.SelectedDates.Add(new DateTime(2024, 8, 5));
    monthCalendar1.SelectedDates.Add(new DateTime(2024, 8, 10));
    monthCalendar1.SelectedDates.Add(new DateTime(2024, 8, 15));
}
3. 快速定位到指定日期

通过SetDateGoToDate方法跳转到特定日期:

// 跳转到2024年12月(不改变选择,仅滚动到该月份)
monthCalendar1.GoToDate(new DateTime(2024, 12, 1));
​
// 跳转到并选中2024年12月25日
monthCalendar1.SetDate(new DateTime(2024, 12, 25));
4. 限制可选择的日期(如仅工作日)

通过DateSelected事件校验选择,若包含非工作日则取消选择:

private void monthCalendar1_DateSelected(object sender, DateRangeEventArgs e)
{
    // 检查选择范围内是否包含周末(周六或周日)
    for (DateTime dt = e.Start; dt <= e.End; dt = dt.AddDays(1))
    {
        if (dt.DayOfWeek == DayOfWeek.Saturday || dt.DayOfWeek == DayOfWeek.Sunday)
        {
            MessageBox.Show("不可选择周末!");
            // 恢复到上一次选择
            monthCalendar1.SelectionStart = lastStart;
            monthCalendar1.SelectionEnd = lastEnd;
            return;
        }
    }
    // 记录当前选择(用于恢复)
    lastStart = e.Start;
    lastEnd = e.End;
}

六、常见问题与注意事项

  1. 选择范围超过MaxSelectionCount 若用户拖动选择的天数超过MaxSelectionCount,控件会自动截断选择(保留前MaxSelectionCount天)。如需自定义提示,可在DateSelected事件中判断并处理。

  2. 清除选择的日期 使用SelectedDates.Clear()清空选择,或SetDate(DateTime.Today)重置为今天。

  3. 控件大小调整 MonthCalendar的大小由显示的月份数量决定(CalendarDimensions),手动设置Size可能导致显示不全,建议通过调整CalendarDimensions控制大小。

  4. 多语言与本地化 日历的月份 / 星期显示语言跟随系统区域设置,若需固定语言,需通过操作系统的区域设置修改。

七、与DateTimePicker的适用场景对比

控件优势场景局限性
MonthCalendar选择日期范围、查看多个月份、标记特殊日期占用空间较大,不适合仅需单个日期的简单场景
DateTimePicker单个日期 / 时间选择、节省界面空间、支持时间选择不支持范围选择,无法同时显示多个月份

总结

MonthCalendar是处理日期范围选择和多月份查看的理想控件,通过灵活设置选择范围、高亮日期和显示格式,可满足酒店预订、日程安排等场景需求。使用时需注意选择限制的处理和界面空间的合理分配,结合DateSelected事件可实现实时交互反馈。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张謹礧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值