【问题标题】:A DateTimePicker to change only month and year仅更改月份和年份的 DateTimePicker
【发布时间】:2021-07-09 00:59:36
【问题描述】:

UI 应该保持不变我不想这样做:

dateTimePicker1.Format = DateTimePickerFormat.Custom;
dateTimePicker1.CustomFormat = "mm-yyyy";
dateTimePicker1.ShowUpDown = true; 

用户可以选择年份和月份,将 DateTimePicker 更改为 Month/Year 选择器,MonthCalendar 也是。
我不想使用第三方控件,但如果它是唯一的答案,我会使用任何免费的月/年选择器控件。

【问题讨论】:

  • 您是否考虑过只使用两个下拉菜单(一个用于月份,一个用于年份)?对于普通日期,日历很有帮助,因此用户可以查看特定日期是星期几;仅选择月份和年份时,该功能就没有那么有用了。

标签: c# .net winforms custom-controls datetimepicker


【解决方案1】:

这是一个简单的 DateTimePicker 自定义控件,它预定义了自定义 DateTime 格式并修改了 MonthCalendar 视图,配置它只显示打开时的月份和年份。

我添加了一个公共属性 ShowToday,它允许指定 MonthCalendar 弹出窗口是否应在日历界面底部显示 Today 日期。

自定义控件覆盖 OnDropDown 以获取 MonthCalendar 弹出窗口的句柄,发送 DTM_GETMONTHCAL 消息并更改其当前视图发送 MCM_SETCURRENTVIEW,指定 MCMV_YEAR 作为值参数。

这就是它的样子:


using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;

[DesignerCategory("Code")]
class DateTimePickerYearMonth : DateTimePicker
{
    public DateTimePickerYearMonth() {
        this.CustomFormat = "MM-yyyy";
        this.Format = DateTimePickerFormat.Custom;
        this.Value = DateTime.Now;
    }

    [
        Browsable(true), EditorBrowsable(EditorBrowsableState.Always), DefaultValue(false),
        Category("Appearance"), 
        Description("Shows or hides \"Today\" date at the bottom of the Calendar Control")
    ]
    public bool ShowToday {
        get => m_ShowToday;
        set {
            if (value != m_ShowToday) {
                m_ShowToday = value;
                ShowMonCalToday(m_ShowToday);
            }
        }
    }

    protected override void OnHandleCreated(EventArgs e)
    {
        base.OnHandleCreated(e);
        ShowMonCalToday(m_ShowToday);
    }

    protected override void OnDropDown(EventArgs e)
    {
        var hWnd = SendMessage(this.Handle, DTM_GETMONTHCAL, 0, 0);
        if (hWnd != IntPtr.Zero) {
            SendMessage(hWnd, MCM_SETCURRENTVIEW, 0, (int)MonCalView.MCMV_YEAR);
        }
        base.OnDropDown(e);
    }

    private void ShowMonCalToday(bool show)
    {
        int styles = SendMessage(this.Handle, DTM_GETMCSTYLE, 0, 0).ToInt32();
        styles = show ? styles &~(int)MonCalStyles.MCS_NOTODAY : styles | (int)MonCalStyles.MCS_NOTODAY;
        SendMessage(this.Handle, DTM_SETMCSTYLE, 0, styles);
    }
        
    [DllImport("user32.dll")]
    static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

    private const int DTM_FIRST = 0x1000;
    private const int DTM_GETMONTHCAL = DTM_FIRST + 8;
    private const int DTM_SETMCSTYLE = DTM_FIRST + 11;
    private const int DTM_GETMCSTYLE = DTM_FIRST + 12;
    private const int MCM_FIRST = 0x1000;
    private const int MCM_GETCURRENTVIEW = MCM_FIRST + 22;
    private const int MCM_SETCURRENTVIEW = MCM_FIRST + 32;
    private bool m_ShowToday = false;

    public enum MonCalView : int
    {
        MCMV_MONTH = 0,
        MCMV_YEAR = 1,
        MCMV_DECADE = 2,
        MCMV_CENTURY = 3
    }

    public enum MonCalStyles : int
    {
        MCS_DAYSTATE = 0x0001,
        MCS_MULTISELECT = 0x0002,
        MCS_WEEKNUMBERS = 0x0004,
        MCS_NOTODAYCIRCLE = 0x0008,
        MCS_NOTODAY = 0x0010,
        MCS_NOTRAILINGDATES = 0x0040,
        MCS_SHORTDAYSOFWEEK = 0x0080,
        MCS_NOSELCHANGEONNAV = 0x0100
    }
}

【讨论】:

    【解决方案2】:

    自定义格式用于确定应在系统/数据库中捕获日期的方式,无论用户选择什么,它不用于限制用户选择月份或年份。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-05
      • 2015-08-17
      • 2014-08-07
      • 2021-01-15
      • 1970-01-01
      • 2013-09-23
      • 2018-06-28
      • 2011-06-11
      相关资源
      最近更新 更多