在 WinForm 中,MonthCalendar
是一个用于直观展示日历并支持日期选择的控件,与DateTimePicker
相比,它更适合选择日期范围(如入住 / 离店时间、假期起止日期)或需要同时查看多个月份的场景。它能显示一个或多个月份的完整日历网格,支持单个日期、连续多日或不连续日期的选择。
一、控件简介
MonthCalendar
的核心特点:
-
可显示 1 个或多个月份(通过
CalendarDimensions
设置行列数); -
支持选择单个日期、连续日期范围或多个不连续日期;
-
可高亮显示特定日期(如节假日、截止日);
-
提供直观的翻页按钮(切换月份 / 年份)和今天日期快速定位。
二、核心属性(表格整理)
属性名称 | 类型 | 说明 |
---|---|---|
SelectionStart | DateTime | 获取或设置选择范围的起始日期(连续选择时有效) |
SelectionEnd | DateTime | 获取或设置选择范围的结束日期(连续选择时有效) |
SelectedDates | SelectedDatesCollection | 包含所有选中的日期(支持不连续选择,通过Add /Remove 方法操作) |
MaxSelectionCount | int | 设置最大可选择的天数(默认 7 天,0 表示无限制,连续选择时生效) |
MinDate | DateTime | 可选择的最小日期(早于该日期的日期不可选) |
MaxDate | DateTime | 可选择的最大日期(晚于该日期的日期不可选) |
CalendarDimensions | Size | 设置显示的月份行数和列数(如new Size(2, 2) 表示 2 行 2 列共 4 个月份) |
ShowToday | bool | 是否在底部显示 “今天” 日期(默认true ,点击可快速跳转到今天) |
ShowTodayCircle | bool | 是否用圆圈标记今天日期(默认true ) |
ShowWeekNumbers | bool | 是否在左侧显示周数(默认false ) |
FirstDayOfWeek | DayOfWeek | 设置每周的第一天(如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. 快速定位到指定日期
通过SetDate
或GoToDate
方法跳转到特定日期:
// 跳转到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; }
六、常见问题与注意事项
-
选择范围超过
MaxSelectionCount
若用户拖动选择的天数超过MaxSelectionCount
,控件会自动截断选择(保留前MaxSelectionCount
天)。如需自定义提示,可在DateSelected
事件中判断并处理。 -
清除选择的日期 使用
SelectedDates.Clear()
清空选择,或SetDate(DateTime.Today)
重置为今天。 -
控件大小调整
MonthCalendar
的大小由显示的月份数量决定(CalendarDimensions
),手动设置Size
可能导致显示不全,建议通过调整CalendarDimensions
控制大小。 -
多语言与本地化 日历的月份 / 星期显示语言跟随系统区域设置,若需固定语言,需通过操作系统的区域设置修改。
七、与DateTimePicker
的适用场景对比
控件 | 优势场景 | 局限性 |
---|---|---|
MonthCalendar | 选择日期范围、查看多个月份、标记特殊日期 | 占用空间较大,不适合仅需单个日期的简单场景 |
DateTimePicker | 单个日期 / 时间选择、节省界面空间、支持时间选择 | 不支持范围选择,无法同时显示多个月份 |
总结
MonthCalendar
是处理日期范围选择和多月份查看的理想控件,通过灵活设置选择范围、高亮日期和显示格式,可满足酒店预订、日程安排等场景需求。使用时需注意选择限制的处理和界面空间的合理分配,结合DateSelected
事件可实现实时交互反馈。