14

So instead of this showing up on clicking the dropdown menu.

enter image description here

I want the dropdown to be like this when clicked.

enter image description here

Thanks a lot for any help. :)

Tyress
  • 3,573
  • 2
  • 22
  • 45
Bigboss
  • 355
  • 1
  • 3
  • 17

5 Answers5

6

Using the windows messages approach, you can detect month calendar control display and force month view and you can detect view changes and close the month calendar control on month to day views change (after a month selection).

The easiest way to implement it is to override DateTimePicker.

public class MonthPicker : DateTimePicker
{
    // initialize Format/CustomFormat to display only month and year.
    public MonthPicker()
    {
        Format = DateTimePickerFormat.Custom;
        CustomFormat = "MMMM yyyy";
    }

    // override Format to redefine default value (used by designer)
    [DefaultValue(DateTimePickerFormat.Custom)]
    public new DateTimePickerFormat Format
    {
        get => base.Format;
        set => base.Format = value;
    }

    // override CustomFormat to redefine default value (used by designer)
    [DefaultValue("MMM yyyy")]
    public new string CustomFormat
    {
        get => base.CustomFormat;
        set => base.CustomFormat = value;
    }

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_NOFITY)
        {
            var nmhdr = (NMHDR)Marshal.PtrToStructure(m.LParam, typeof(NMHDR));
            switch (nmhdr.code)
            {
                // detect pop-up display and switch view to month selection
                case -950:
                {
                    var cal = SendMessage(Handle, DTM_GETMONTHCAL, IntPtr.Zero, IntPtr.Zero);
                    SendMessage(cal, MCM_SETCURRENTVIEW, IntPtr.Zero, (IntPtr)1);
                    break;
                }

                // detect month selection and close the pop-up
                case MCN_VIEWCHANGE:
                {
                    var nmviewchange = (NMVIEWCHANGE)Marshal.PtrToStructure(m.LParam, typeof(NMVIEWCHANGE));
                    if (nmviewchange.dwOldView == 1 && nmviewchange.dwNewView == 0)
                    {
                        SendMessage(Handle, DTM_CLOSEMONTHCAL, IntPtr.Zero, IntPtr.Zero);
                    }

                    break;
                }
            }
        }
        base.WndProc(ref m);
    }

    private const int WM_NOFITY = 0x004e;
    private const int DTM_CLOSEMONTHCAL = 0x1000 + 13;
    private const int DTM_GETMONTHCAL = 0x1000 + 8;
    private const int MCM_SETCURRENTVIEW = 0x1000 + 32;
    private const int MCN_VIEWCHANGE = -750;

    [DllImport("user32.dll")]
    public static extern IntPtr SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);

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

    [StructLayout(LayoutKind.Sequential)]
    struct NMVIEWCHANGE
    {
        public NMHDR nmhdr;
        public uint dwOldView;
        public uint dwNewView;
    }
}
Orace
  • 7,822
  • 30
  • 45
  • @ZulqarnainJalil can you provide more information and context ? What did not work ? What platform did you use ?, etc... – Orace Jan 10 '20 at 09:27
  • I am using C# windows form application on Visualstudio 2017. and i have copied your code in my form1.cs class and nothing happens to my calendar control that i added in my form1 – Zulqarnain Jalil Jan 10 '20 at 10:38
  • 1
    That's not how it's work. This is a custom user control. Try get infos on this subject. – Orace Jan 10 '20 at 11:32
  • sure... i will try :) – Zulqarnain Jalil Jan 10 '20 at 15:36
  • 2
    @ZulqarnainJalil, put the code in a separate MonthPicker.cs file. Compile. Open Form1 designer. The control will appear in the ToolBox windows in the "*{AppName} Components*" section and is named "*MonthPicker*". Add it as a new component in the main form. Et Voilà. – Orace Jan 10 '20 at 15:44
4

Why you need to do this? If you want to display Months only then easier way is to have a list of months in Combox.

However I found something for you on msdn. Have a look here https://social.msdn.microsoft.com/Forums/en-US/7bdca56f-719e-44bf-be6d-a9600dfa8f78/wpf-datepicker-for-months-only?forum=wpf

Dk358
  • 179
  • 1
  • 7
  • because I only need the user to select a month and don't want to mislead them in thinking that the date should also be accurate, hence the only thing important is month. – Bigboss Jan 18 '16 at 02:53
  • 2
    @Bigboss A list of months in a ComboBox is the standard solution for what you require. – Jeremy Thompson Jan 18 '16 at 04:00
  • 1
    @JeremyThompson, but how about if I want a year? – Bigboss Jan 18 '16 at 08:30
  • @Bigboss Did you get chance to have a look at the link. Well just brief explanation here, it talks about Calendar control in WPF Toolkit and it does have three DisplayModes. One is Decade that may suit your needs. P.S. I haven't tried it but I guess it will be worth trying that. Otherwise again a Combox do. – Dk358 Jan 19 '16 at 00:39
1

Try the following code:

DateTime newDateValue = new DateTime(dateTimePicker_month.Value.Year, 1, 1);
dateTimePicker_month.Value = newDateValue;
dateTimePicker_month.Format = DateTimePickerFormat.Custom;
dateTimePicker_month.CustomFormat = "MMM-yyyy";
dateTimePicker_month.ShowUpDown = true;

You have to add (1,1) for february month which having 28/29 days to ascertain the all the month values.If you want the query to select month.Following is an example:

string month = dateTimePicker_month.Value.Month.ToString();
string year = dateTimePicker_month.Value.Year.ToString();

use the following query to select month:

select CAST(date AS DATE) from table where DATEPART(month, date)  = '" + month + "' and DATEPART(year,date) = '" + year + "' 
manraj
  • 151
  • 7
1

As didn't work in my case I modified Orance's answer, putting this in a class inherited from DateTimePicker :

    protected override void WndProc(ref Message m)
{
    if (_MonthSelectStyle)
    {
        if (m.Msg == 0X204E) // = Win32Messages.WM_REFLECT_NOTIFY
        {
            var nmhdrI = (NMHDR)(Marshal.PtrToStructure(m.LParam, typeof(NMHDR)));
            switch (nmhdrI.code)
            {
                case -754: // Win32Messages.DTN_DROPDOWN
                    var cal = SendMessage(m.HWnd, WinApi.Win32Messages.DTM_GETMONTHCAL, IntPtr.Zero, IntPtr.Zero);
                    SendMessage(cal, WinApi.Win32Messages.MCM_SETCURRENTVIEW, IntPtr.Zero, (IntPtr)1);
                    break;
                case -759: // Win32Messages.DTN_DATETIMECHANGE
                    WinApi.SendMessage(Handle, WinApi.Win32Messages.DTM_CLOSEMONTHCAL, IntPtr.Zero, IntPtr.Zero);
                    break;
            }
        }
    }
    base.WndProc(ref m);
}

And the VB equivalent:

    Protected Overrides Sub WndProc(ByRef m As Message)
    If _MonthSelectStyle Then
        If m.Msg = &H204E Then ' WM_REFLECT_NOTIFY  '&H204E   
          Dim nmhdrI = CType(Marshal.PtrToStructure(m.LParam, GetType(NMHDR)), NMHDR)
            Select Case nmhdrI.code
                Case -754 ' Win32Messages.DTN_DROPDOWN '-754  
                    Dim cal = SendMessage(m.HWnd, WinApi.Win32Messages.DTM_GETMONTHCAL, IntPtr.Zero, IntPtr.Zero)
                    SendMessage(cal, WinApi.Win32Messages.MCM_SETCURRENTVIEW, IntPtr.Zero, CType(1, IntPtr))
                Case -759 ' Win32Messages.DTN_DATETIMECHANGE '-759  
                    WinApi.SendMessage(Handle, WinApi.Win32Messages.DTM_CLOSEMONTHCAL, IntPtr.Zero, IntPtr.Zero)
            End Select
        End If
    End If
    MyBase.WndProc(m)
End Sub
anefeletos
  • 672
  • 7
  • 19
0

Try using Format properties:

 dateTimePicker.Format = DateTimePickerFormat.Custom;
 dateTimePicker.CustomFormat = "MM";
FrozenFire
  • 671
  • 14
  • 28
  • Already tried this. The only that is changed is the display but when the dropdown menu is clicked. It still shows the days. – Bigboss Jan 18 '16 at 02:41
  • 1
    See my updated answer. I think you need to replaceDatePicker with MonthCalendar if you want to show the calendar without day. – FrozenFire Jan 18 '16 at 02:48
  • I have read ur edits but what options should I change in the MonthCalendar Class. I believe that this class is the one used by datetimepicker when clicking the dropdown menu. – Bigboss Jan 18 '16 at 02:51
  • I found this solution: https://netprogrammingodyssey.wordpress.com/2010/11/14/monthyear-only-datepicker/ but you need to add silverlight to your project to implement this. – FrozenFire Jan 18 '16 at 03:17