Fame th
Fame th

Reputation: 1038

The Date of the MonthCalendar of a DateTimePicker is not updated

At startup, I set DateTimePicker Value to the Minimum Date value.
The Date is changed to the current Date when a User clicks the DateTimePicker, using the MouseDown event.
A TextBox is changed to the current date, but the pop-up Calendar is not updated and still shows the original Date.

Private Sub frm1_Load(sender As Object, e As EventArgs) Handles Me.Load        
        dtpReceiveDate.Value = clsCommon.NULL_DATE     
End Sub

 Private Sub dtpReceiveDate_MouseDown(sender As Object, e As MouseEventArgs) Handles dtpReceiveDate.MouseDown       
        dtpReceiveDate.Value = Today       
End Sub

enter image description here

Upvotes: 2

Views: 607

Answers (1)

Jimi
Jimi

Reputation: 32223

The MouseDown event is raised after the MonthCalendar Control of your DateTimePicker has been updated with the current DateTime value.
In case the MouseDown event is generated on the Button that opens the MonthCalendar.
Clicking on the date section of the Control, doesn't cause the MonthCalendar to open.

I suggest not to use the MouseDown event to update the Value of the DateTimePicker, since this will cause the Date to reset each time a User clicks anywhere on the Control. It could be unnerving (it's up to you anyway).
You can use the DropDown event instead: it's raised only when a User Clicks on the down-arrow Button.

▶ You cannot use the ValueChanged event with the code shown here: this might cause a deadlock (given the nature of the Win32 Controls involved and the use of SendMessage, it's the type of deadlock that may spread to the entire System, so, don't).

The DtpUpdateMonthCalendardDate() method here sends a DTM_GETMONTHCAL message to the DateTimePicker passed as argument.
If the Handle of the MonthCalendar is acquired successfully, it then sends a MCM_SETCURSEL message to the MonthCalendar Control to align its Date to the Date of the parent DateTimePicker.
The new Date is passed using a SYSTEMTIME structure initialized with the Value of the DateTimePicker.

Private Sub dtpReceiveDate_DropDown(sender As Object, e As EventArgs) Handles dtpReceiveDate.DropDown
    dtpReceiveDate.Value = Date.Today
    ' If result is False, something went wrong and the Date is not set
    Dim result = DtpUpdateMonthCalendardDate(dtpReceiveDate)
End Sub

Private Function DtpUpdateMonthCalendardDate(dtp As DateTimePicker) As Boolean
    If Not dtp.IsHandleCreated OrElse dtp.ShowUpDown Then Return False

    Dim hWndCal = SendMessage(dtp.Handle, DTM_GETMONTHCAL, 0, 0)
    If hWndCal = IntPtr.Zero Then Return False

    Dim sysTime = New SYSTEMTIME(dtp.Value)
    Return SendMessage(hWndCal, MCM_SETCURSEL, 0, sysTime) <> 0
End Function

Win32 declarations:

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_GETCURSEL As Integer = MCM_FIRST + 1
Friend Const MCM_SETCURSEL As Integer = MCM_FIRST + 2

<StructLayout(LayoutKind.Sequential)>
Friend Structure SYSTEMTIME
    Public Year As Short
    Public Month As Short
    Public DayOfWeek As Short
    Public Day As Short
    Public Hour As Short
    Public Minute As Short
    Public Second As Short
    Public Milliseconds As Short

    Public Sub New(dt As Date)
        Year = CShort(dt.Year)
        Month = CShort(dt.Month)
        DayOfWeek = CShort(dt.DayOfWeek)
        Day = CShort(dt.Day)
        Hour = CShort(dt.Hour)
        Minute = CShort(dt.Minute)
        Second = CShort(dt.Second)
        Milliseconds = CShort(dt.Millisecond)
    End Sub

    Public Function ToDateTime() As Date
        Return New DateTime(Year, Month, Day, Hour, Minute, Second, Milliseconds)
    End Function
End Structure

<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

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

Upvotes: 3

Related Questions