简体   繁体   English

如何将 DateTimePicker 下拉菜单设置为 select 年或月?

[英]How can I set the DateTimePicker dropdown to select Years or Months only?

Like discussed in How can I set the datetimepicker dropdown to show Months only there was a possibility to overwrite DateTimePicker to get a MonthPicker .就像在我如何设置 datetimepicker 下拉列表以仅显示 Months中讨论的那样,有可能覆盖DateTimePicker以获得MonthPicker

I have read a lot of sites but didn't figure out how to do similar to get a YearPicker .我已经阅读了很多网站,但没有弄清楚如何做类似的事情来获得YearPicker
Maybe someone can help out.也许有人可以帮忙。

This Custom Control tweaks a little the standard DateTimePicker to get a Year or Month selection style only.此自定义控件对标准 DateTimePicker 稍作调整,以仅获得年份或月份选择样式。

▶ The standard DateTimePicker's CustomFormat and Format properties are disabled , setting internally the former to yyyy or MMMM (a simple modification can add different formats) and the latter to DateTimePickerFormat.Custom . ▶ 标准 DateTimePicker 的CustomFormatFormat属性被禁用,在内部将前者设置为yyyyMMMM (简单修改可以添加不同的格式),将后者设置为DateTimePickerFormat.Custom These properties are hidden from the PropertyGrid an cannot be changed.这些属性在 PropertyGrid 中是隐藏的,无法更改。

▶ The browsing functionality is maintained, but limited to the Decade/Year or Decade/Year/Month selection. ▶ 保留浏览功能,但仅限于十年/年或十年/年/月选择。
Clicking the DTP's Title Area, brings on the Decade selector and the previous and next Buttons are of course functional (these can only show years).单击 DTP 的标题区域,打开十年选择器,上一个和下一个按钮当然可以正常工作(这些只能显示年份)。

▶ The DTP is closed and the current value set when a MCN_VIEWCHANGE notification reveals, passing the current selection level in a NMVIEWCHANGE structure, that the current selection has reached the View Mode set by the SelectionMode property. ▶ DTP 关闭并在MCN_VIEWCHANGE通知显示时设置当前值,通过NMVIEWCHANGE结构中的当前选择级别,当前选择已达到由SelectionMode属性设置的查看模式。
This property value is an enumerator which, in turn, reflects the MonthCalendar's MCM_SETCURRENTVIEW message values.此属性值是一个枚举器,它反过来反映 MonthCalendar 的MCM_SETCURRENTVIEW消息值。

▶ The current View is set sending a MCM_SETCURRENTVIEW message to the MonthCalendar control, changing the default View to MCMV_DECADE or MCMV_YEAR (depending on the current SelectionMode ) each time the MonthCalendar control is shown. ▶ 当前视图设置为向 MonthCalendar 控件发送MCM_SETCURRENTVIEW消息,每次显示 MonthCalendar 控件时将默认视图更改为MCMV_DECADEMCMV_YEAR (取决于当前SelectionMode )。 The opening animation is then preserved.然后保留开口 animation。

▶ The only style changed is MCS_NOTODAY , set in the OnHandleCreated method. ▶ 唯一更改的样式是MCS_NOTODAY ,在OnHandleCreated方法中设置。 It can be switched on/off at any time, calling the ShowMonCalToday() method.它可以随时打开/关闭,调用ShowMonCalToday()方法。
This style shows the Today date, at the bottom of the DateTimerPicker.此样式在 DateTimerPicker 底部显示Today日期。 It sets the current Year or Month value when clicked.单击时,它会设置当前的年或月值。


This is how it works:这是它的工作原理:

DateTimePicker 年仅月

Tested on VisualStudio 2017.在 VisualStudio 2017 上测试。
.Net Framework 4.8 (only). .Net Framework 4.8(仅限)。

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

[DesignerCategory("Code")]
public class MonthYearPicker : DateTimePicker
{
    private string m_CustomFormat = "yyyy";
    private DateTimePickerFormat m_Format = DateTimePickerFormat.Custom;
    private SelectionViewMode m_SelectionMode = SelectionViewMode.Year;
    private bool m_ShowToday = false;
    private IntPtr hWndCal = IntPtr.Zero;

    public MonthYearPicker() {
        base.CustomFormat = m_CustomFormat;
        base.Format = m_Format;
    }

    [DefaultValue(SelectionViewMode.Year)]
    [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
    [Category("Appearance"), Description("Set the current selection mode to either Month or Year")]
    public SelectionViewMode SelectionMode {
        get => m_SelectionMode;
        set {
            if (value != m_SelectionMode) {
                m_SelectionMode = value;
                m_CustomFormat = m_SelectionMode == SelectionViewMode.Year ? "yyyy" : "MMMM";
                base.CustomFormat = m_CustomFormat;
            }
        }
    }

    [DefaultValue(false)]
    [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
    [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);
            }
        }
    }

    [DefaultValue("yyyy")]
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
    public new string CustomFormat {
        get => base.CustomFormat;
        set => base.CustomFormat = m_CustomFormat;
    }

    [DefaultValue(DateTimePickerFormat.Custom)]
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
    public new DateTimePickerFormat Format {
        get => base.Format;
        set => base.Format = m_Format;
    }

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

    protected override void OnDropDown(EventArgs e)
    {
        hWndCal = SendMessage(this.Handle, DTM_GETMONTHCAL, 0, 0);
        if (hWndCal != IntPtr.Zero) {
            SendMessage(hWndCal, MCM_SETCURRENTVIEW, 0, (int)(MonCalStyles)m_SelectionMode);
        }
        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);
    }

    protected override void WndProc(ref Message m)
    {
        switch (m.Msg) {
            case WM_NOTIFY:
                var nmh = (NMHDR)m.GetLParam(typeof(NMHDR));
                switch (nmh.code) {
                    case MCN_VIEWCHANGE:
                        var nmView = (NMVIEWCHANGE)m.GetLParam(typeof(NMVIEWCHANGE));
                        if (nmView.dwNewView < (MonCalView)m_SelectionMode) {
                            SendMessage(this.Handle, DTM_CLOSEMONTHCAL, 0, 0);
                        }
                        break;
                    default:
                        // NOP: Add more notifications handlers...
                        break;
                }
                break;
            default:
                // NOP: Add more message handlers...
                break;
        }
        base.WndProc(ref m);
    }

    public enum SelectionViewMode : int
    {
        Month = MonCalView.MCMV_YEAR,
        Year = MonCalView.MCMV_DECADE,
    }

    // Move to a NativeMethods class, eventually
    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    internal static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

    internal const int WM_NOTIFY = 0x004E;
    internal const int MCN_VIEWCHANGE = -750;

    internal const int DTM_FIRST = 0x1000;
    internal const int DTM_GETMONTHCAL = DTM_FIRST + 8;
    internal const int DTM_SETMCSTYLE = DTM_FIRST + 11;
    internal const int DTM_GETMCSTYLE = DTM_FIRST + 12;
    internal const int DTM_CLOSEMONTHCAL = DTM_FIRST + 13;

    internal const int MCM_FIRST = 0x1000;
    internal const int MCM_GETCURRENTVIEW = MCM_FIRST + 22;
    internal const int MCM_SETCURRENTVIEW = MCM_FIRST + 32;

    [StructLayout(LayoutKind.Sequential)]
    internal struct NMHDR
    {
        public IntPtr hwndFrom;
        public UIntPtr idFrom;
        public int code;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct NMVIEWCHANGE
    {
        public NMHDR nmhdr;
        public MonCalView dwOldView;
        public MonCalView dwNewView;
    }

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

    internal 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
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将 datetimepicker 下拉菜单设置为仅显示月份 - How can I set the datetimepicker dropdown to show Months only 如何在WPF DatePicker中仅选择年份(或月份)? - How to select only years (or months) in WPF DatePicker? 仅使用DropDown选择DateTimePicker - DateTimePicker selection only with DropDown 如何从提供的年份填充“月”组合框和“年”组合框,并将它们的值默认为上个月? - How can I populate a "Months" combobox and a "Years" combobox from a supplied year, and have their values default to the last month? 如何通过使用 DateTime 列和可变月份、年份的查询来填充记录 - How can I populate an Array with records via a query using DateTime column and variable months, years 如何限制DateTimePicker只更改日期,而不是时间? - How can I limit the DateTimePicker to only change the date, not the time? 如何以编程方式关闭 datetimepicker 的下拉日历或更新下拉日历以反映 .Value 属性? - How can I programmatically close the dropdown calendar of a datetimepicker or update the dropdown calendar to reflect the .Value property? 如何将DateTimePicker值设置为今天的日期+ 1 - How can I set a DateTimePicker value as today's date+1 如何将日期时间选择器设置为具有自定义时间的星期一? - How can I set datetimepicker to Monday with customized time? 如何将 DateTimePicker 控件设置为特定日期? - How can I set a DateTimePicker control to a specific date?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM