1

Using the traditional DateTimePicker control in a winforms environment in a vb.net or c# application I need to change how the week is displayed from the normal Sunday through Saturday to Tuesday through Monday. I have scoured Google and Stack and found nothing on this. I have no issue with creating a custom control. I just don't know where to start.

KJM
  • 83
  • 1
  • 7

1 Answers1

3

You can use SendMessage to send a MCM_SETFIRSTDAYOFWEEK message to the MonthCalendar of the DateTimePicker (read the notes related to this message in the Docs).

You first send a DTM_GETMONTHCAL message to get the handle of the MonthCalendar control. As shown, you can send this message in the DropDown event handler of the DateTimePicker.
If the handle is valid, set the first day sending MCM_SETFIRSTDAYOFWEEK.
The lParam value determines the first day shown in the MonthCalendar:

0 = Monday, 1 = Tuesday etc.

If you want to build a custom control (IMO, preferable), you can find one pre-built here:
How can I set the DateTimePicker dropdown to select Years or Months only?

It shows how to deal with the DateTimePicker and its MonthCalendar dropdown, to change the current View and similar tasks.

internal const int DTM_FIRST = 0x1000;
internal const int DTM_GETMONTHCAL = DTM_FIRST + 8;
internal const int MCM_FIRST = 0x1000;
internal const int MCM_SETFIRSTDAYOFWEEK = MCM_FIRST + 15;

internal enum MCWeekDay : int 
{
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
}

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

internal void MonthCalendarSetFirstDayOfWeek(IntPtr dtpHandle, MCWeekDay weekDay)
{
    IntPtr hWndCal = SendMessage(dtpHandle, DTM_GETMONTHCAL, 0, 0);
    if (hWndCal != IntPtr.Zero) {
        SendMessage(hWndCal, MCM_SETFIRSTDAYOFWEEK, 0, (int)weekDay);
    }
}

private void dateTimePicker1_DropDown(object sender, EventArgs e)
{
    MonthCalendarSetFirstDayOfWeek((sender as Control).Handle, MCWeekDay.Tuesday);
}

VB.Net version:

Imports System.Runtime.InteropServices

Friend Const DTM_FIRST As Integer = &H1000
Friend Const DTM_GETMONTHCAL As Integer = DTM_FIRST + 8
Friend Const MCM_FIRST As Integer = &H1000
Friend Const MCM_SETFIRSTDAYOFWEEK As Integer = MCM_FIRST + 15

Friend Enum MCWeekDay As Integer
    Monday
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
    Sunday
End Enum

<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
Friend Shared Function SendMessage(hWnd As IntPtr, Msg As Integer, wParam As Integer, lParam As Integer) As IntPtr
End Function

Friend Sub MonthCalendarSetFirstDayOfWeek(dtpHandle As IntPtr, weekDay As MCWeekDay)
    Dim hWndCal As IntPtr = SendMessage(dtpHandle, DTM_GETMONTHCAL, 0, 0)
    If hWndCal <> IntPtr.Zero Then
        SendMessage(hWndCal, MCM_SETFIRSTDAYOFWEEK, 0, weekDay)
    End If
End Sub

Private Sub DateTimePicker1_DropDown(sender As Object, e As EventArgs) Handles DateTimePicker1.DropDown
    MonthCalendarSetFirstDayOfWeek(DirectCast(sender, Control).Handle, MCWeekDay.Tuesday)
End Sub
Jimi
  • 29,621
  • 8
  • 43
  • 61
  • One thing I did notice was if you use the Form_Activated event any calendar change will fire it. Its not a big deal at all for me but in my process of trying to understand Jimi's answer I noticed it. Again brilliant work. – KJM May 10 '20 at 15:31
  • 1
    The use of `SendMessage` doesn't imply a Form activation. If something is causing the Form to lose focus and re-acquire it, that's not this function call, you have something else that causes it. `SendMessage` is the standard way to activate specific functionalities of Win32 controls, it's used constantly all over the framework, you simply cannot *see it*. – Jimi May 10 '20 at 16:54