Winform之MonthCalendar

WinForms MonthCalendar控件完整教程

MonthCalendar是WinForms中用于日期选择的控件,支持单日/多日选择、日期范围限制及样式定制。本教程从基础功能到高级配置进行系统性讲解,结合代码示例与场景应用。


一、控件基础操作

1. 添加控件

  • 拖拽添加:从工具箱→Common Controls→MonthCalendar拖拽至窗体
  • 属性配置
    • Name属性:建议使用mcCalendar前缀命名
    • Dock属性:可设置为Fill实现自适应布局

2. 核心属性详解

属性作用示例代码
MinDate/MaxDate限制可选日期范围mcCalendar.MinDate = new DateTime(2020, 1, 1);
SelectionRange设置默认选中范围mcCalendar.SelectionRange = new SelectionRange(start, end);
ShowToday控制"今天"按钮显示mcCalendar.ShowToday = false;
CalendarDimensions多月显示布局mcCalendar.CalendarDimensions = new Size(2, 1); // 双月横向排列

3. 事件处理

// 单日选择事件
private void mcCalendar_DateSelected(object sender, DateRangeEventArgs e)
{
    MessageBox.Show($"选择日期: {e.Start:yyyy-MM-dd}");
}

// 日期范围变更事件
private void mcCalendar_DateChanged(object sender, DateRangeEventArgs e)
{
    if (e.Start == e.End)
        lblDisplay.Text = $"单日选择: {e.Start:D}";
    else
        lblDisplay.Text = $"范围选择: {e.Start:D}{e.End:D}";
}

二、高级功能实现

1. 日期高亮配置

// 静态高亮(元旦、春节等)
DateTime[] holidays = { new DateTime(2025, 1, 1), new DateTime(2025, 2, 10) };
mcCalendar.BoldedDates = holidays;

// 动态高亮(每月15日)
private void Form_Load(object sender, EventArgs e)
{
    List<DateTime> monthlyDates = new List<DateTime>();
    for (int i = 1; i <= 12; i++)
        monthlyDates.Add(new DateTime(2025, i, 15));
    mcCalendar.MonthlyBoldedDates = monthlyDates.ToArray();
}

2. 跨控件交互

// 工具栏日期选择实现
private void txtStartDate_Click(object sender, EventArgs e)
{
    mcCalendar.Location = txtStartDate.PointToScreen(Point.Empty);
    mcCalendar.Show();
}

private void mcCalendar_DateSelected(object sender, DateRangeEventArgs e)
{
    txtStartDate.Text = e.Start.ToString("yyyy.MM.dd");
    mcCalendar.Hide();
}

3. 多语言支持

// 设置首日为周一
mcCalendar.FirstDayOfWeek = DayOfWeek.Monday;

// 格式化显示
private void mcCalendar_DateChanged(object sender, DateRangeEventArgs e)
{
    lblDisplay.Text = $"选择: {e.Start:yyyy年MM月dd日 dddd}"; // 显示星期名称
}

三、常见场景解决方案

1. 日期范围限制

// 限制选择范围为30天内
mcCalendar.MaxSelectionCount = 30;

// 动态调整最大可选日期
private void UpdateMaxDate()
{
    mcCalendar.MaxDate = DateTime.Now.AddMonths(6); // 最大可选未来6个月
}

2. 特殊日期标记

// 添加红色背景标记
private void mcCalendar_DrawItem(object sender, DrawMonthCalendarEventArgs e)
{
    if (e.Bounds.Height > 0) // 排除标题栏
    {
        if (e.Date.Day == 15) // 每月15日标记
        {
            e.Graphics.FillRectangle(Brushes.LightPink, e.Bounds);
            e.Graphics.DrawString(e.Date.Day.ToString(), 
                                e.Font, 
                                Brushes.Red, 
                                e.Bounds);
            return;
        }
    }
    e.DrawBackground();
    e.DrawText();
}

3. 数据验证

// 验证日期有效性
private bool ValidateDateRange(DateTime start, DateTime end)
{
    if (start > end)
    {
        errorProvider.SetError(mcCalendar, "结束日期必须晚于开始日期");
        return false;
    }
    errorProvider.Clear();
    return true;
}

四、性能优化建议

  1. 事件节流:对频繁触发的DateChanged事件添加防抖处理
  2. 资源释放:在窗体关闭时调用Dispose()释放控件资源
  3. 多线程处理:大数据量日期计算时使用BackgroundWorker

五、完整示例代码

public partial class DateSelectorForm : Form
{
    public DateSelectorForm()
    {
        InitializeComponent();
        
        // 基础配置
        mcCalendar.MinDate = DateTime.Now.AddYears(-1);
        mcCalendar.MaxDate = DateTime.Now.AddYears(1);
        mcCalendar.CalendarDimensions = new Size(2, 1);
        
        // 事件绑定
        mcCalendar.DateSelected += McCalendar_DateSelected;
        mcCalendar.DrawItem += McCalendar_DrawItem;
        
        // 初始化标记
        InitializeBoldedDates();
    }

    private void InitializeBoldedDates()
    {
        // 节假日标记
        DateTime[] holidays = {
            new DateTime(2025, 1, 1), new DateTime(2025, 2, 10),
            new DateTime(2025, 5, 1), new DateTime(2025, 10, 1)
        };
        mcCalendar.BoldedDates = holidays;
        
        // 每月15日标记
        List<DateTime> monthlyDates = new List<DateTime>();
        for (int i = 1; i <= 12; i++)
            monthlyDates.Add(new DateTime(2025, i, 15));
        mcCalendar.MonthlyBoldedDates = monthlyDates.ToArray();
    }

    private void McCalendar_DateSelected(object sender, DateRangeEventArgs e)
    {
        if (e.Start == e.End)
            lblResult.Text = $"单日选择: {e.Start:yyyy-MM-dd}";
        else
            lblResult.Text = $"范围选择: {e.Start:yyyy-MM-dd}{e.End:yyyy-MM-dd}";
    }

    private void McCalendar_DrawItem(object sender, DrawMonthCalendarEventArgs e)
    {
        if (e.Bounds.Height > 0)
        {
            // 节假日红色显示
            if (Array.Exists(mcCalendar.BoldedDates, d => d == e.Date))
            {
                e.Graphics.FillRectangle(Brushes.LightCoral, e.Bounds);
                e.Graphics.DrawString(e.Date.Day.ToString(), 
                                    e.Font, 
                                    Brushes.White, 
                                    e.Bounds);
                return;
            }
            
            // 每月15日蓝色显示
            if (e.Date.Day == 15)
            {
                e.Graphics.FillRectangle(Brushes.LightBlue, e.Bounds);
                e.Graphics.DrawString(e.Date.Day.ToString(), 
                                    e.Font, 
                                    Brushes.Black, 
                                    e.Bounds);
                return;
            }
        }
        e.DrawBackground();
        e.DrawText();
    }
}

六、注意事项

  1. 时区处理:涉及跨时区应用时需使用DateTimeOffset类型
  2. 无障碍支持:为视力障碍用户添加ToolTip控件
  3. 本地化适配:日期格式需根据CultureInfo.CurrentCulture动态调整

通过以上配置,MonthCalendar控件可满足90%以上的日期选择场景需求。对于更复杂的需求(如节假日计算),建议结合第三方库(如NodaTime)实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值