Imports System.Runtime.InteropServices
Public Class DateTimePickerEx
Inherits System.Windows.Forms.DateTimePicker
#Region " API "
<StructLayout(LayoutKind.Sequential)> _
Private Structure SYSTEMTIME
<MarshalAs(UnmanagedType.U2)> Public Year As Short
<MarshalAs(UnmanagedType.U2)> Public Month As Short
<MarshalAs(UnmanagedType.U2)> Public DayOfWeek As Short
<MarshalAs(UnmanagedType.U2)> Public Day As Short
<MarshalAs(UnmanagedType.U2)> Public Hour As Short
<MarshalAs(UnmanagedType.U2)> Public Minute As Short
<MarshalAs(UnmanagedType.U2)> Public Second As Short
<MarshalAs(UnmanagedType.U2)> Public Milliseconds As Short
End Structure
<StructLayout(LayoutKind.Sequential)> _
Private Structure RECT
Public left As Integer
Public top As Integer
Public right As Integer
Public bottom As Integer
Public Shared Widening Operator CType(rc As RECT) As Rectangle
Return New Rectangle(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top)
End Operator
End Structure
<StructLayout(LayoutKind.Sequential)> _
Private Structure MCGRIDINFO
Public cbSize As UInt32
Public dwPart As Integer
Public dwFlags As Integer
Public iCalendar As Integer
Public iRow As Integer
Public iCol As Integer
Public bSelected As Boolean
Public stStart As SYSTEMTIME
Public stEnd As SYSTEMTIME
Public rc As RECT
<MarshalAs(UnmanagedType.LPWStr)> Public pszName As String
Public cchName As UInteger
End Structure
Private Delegate Function WinProcDelegate(ByVal Handle As IntPtr, ByVal wMsg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Int32
Private Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hWnd As IntPtr, ByVal nFlag As Integer, ByVal dwNewLong As WinProcDelegate) As IntPtr
Private Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hWnd As IntPtr, ByVal nFlag As Integer, ByVal dwNewLong As IntPtr) As IntPtr
Private Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As IntPtr, ByVal hWnd As IntPtr, ByVal msg As Int32, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Int32
Private Declare Auto Function SendMessage Lib "user32.dll" (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
Private Declare Auto Function SendMessage Lib "user32.dll" (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As IntPtr, ByRef info As MCGRIDINFO) As IntPtr
Private Declare Auto Function GetWindowDC Lib "user32.dll" (ByVal hWnd As IntPtr) As IntPtr
Private Const DTM_GETMONTHCAL As Integer = &H1008
Private Const GWL_WNDPROC = -4
Private Const WM_DESTROY = 2
Private Const WM_PAINT = &HF
Private Const WM_ERASEBKGND = &H14
Private Const MCMV_MONTH = 0
Private Const MCM_FIRST = &H1000
Private Const MCM_GETFIRSTDAYOFWEEK = (MCM_FIRST + 16)
Private Const MCM_GETCURRENTVIEW = (MCM_FIRST + 22)
Private Const MCM_GETCALENDARGRIDINFO = (MCM_FIRST + 24)
Private Const MCGIP_CALENDARCONTROL = 0
Private Const MCGIP_CALENDARCELL = 8
Private Const MCGIF_RECT = &H2
#End Region
#Region " Subclass "
Private prevProc As IntPtr
Private Sub Subclass(hwnd As IntPtr)
prevProc = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf WinProc)
End Sub
Private Sub UnSubclass(hwnd As IntPtr)
SetWindowLong(hwnd, GWL_WNDPROC, prevProc)
End Sub
Private Function WinProc(ByVal Handle As IntPtr, ByVal wMsg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Int32
Select Case wMsg
Case WM_DESTROY
Dim ret = CallWindowProc(prevProc, Handle, wMsg, wParam, lParam)
UnSubclass(Handle)
Return ret
Case WM_PAINT
Dim ret = CallWindowProc(prevProc, Handle, wMsg, wParam, lParam)
If SendMessage(Handle, MCM_GETCURRENTVIEW, IntPtr.Zero, IntPtr.Zero) <> MCMV_MONTH Then Return ret
Dim rc As New RECT
Dim info = New MCGRIDINFO
info.cbSize = Marshal.SizeOf(info)
info.iCol = 6
info.dwPart = MCGIP_CALENDARCELL
info.dwFlags = MCGIF_RECT
Dim cols = {5, 6}
If Globalization.DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek = DayOfWeek.Sunday Then cols(0) = 0
Dim dc = GetWindowDC(Handle)
Using g = Graphics.FromHdc(dc)
For row = 0 To 5
For Each col In cols
info.iRow = row
info.iCol = col
Call SendMessage(Handle, MCM_GETCALENDARGRIDINFO, IntPtr.Zero, info)
Using p As New Pen(Color.Gray, 2)
g.DrawLine(p, info.rc.left, info.rc.top, info.rc.right, info.rc.bottom)
g.DrawLine(p, info.rc.right, info.rc.top, info.rc.left, info.rc.bottom)
End Using
Next
Next
End Using
Return ret
Case Else
Return CallWindowProc(prevProc, Handle, wMsg, wParam, lParam)
End Select
End Function
#End Region
Public Sub New()
MyBase.New()
cashedValue = Me.Value
End Sub
Private cashedValue As DateTime, bFromCode As Boolean
Private Sub DateTimePickerEx_DropDown(sender As Object, e As System.EventArgs) Handles Me.DropDown
cashedValue = Me.Value
Dim hMonth As IntPtr = SendMessage(Me.Handle, DTM_GETMONTHCAL, IntPtr.Zero, IntPtr.Zero)
If hMonth <> IntPtr.Zero Then Subclass(hMonth)
End Sub
Private Sub DateTimePickerEx_ValueChanged(sender As Object, e As System.EventArgs) Handles Me.ValueChanged
If Not bFromCode Then
If Me.Value.DayOfWeek = DayOfWeek.Saturday OrElse Me.Value.DayOfWeek = DayOfWeek.Sunday Then
bFromCode = True
Me.Value = cashedValue
bFromCode = False
Else
cashedValue = Me.Value
End If
End If
End Sub
End Class
'Restrict days of week (design time supported)
DateTimePickerEx1.RestrictedDaysOfWeek.AddRange({DayOfWeek.Saturday, DayOfWeek.Sunday})
'Restrict specific dates (design time supported)
DateTimePickerEx1.RestrictedDates.AddRange({New Date(2017, 3, 1), New Date(2017, 4, 1)})
'Restrict days for each year
DateTimePickerEx1.RestrictedDaysOfYear.Add(New DayOfYear With {.Month = 12, .Day = 25})
'Restrict before specific date
DateTimePickerEx1.RestrictBefore(New Date(2017, 1, 1))
'Restrict after specific date
DateTimePickerEx1.RestrictAfter(New Date(2017, 12, 31))
3. Showing "No" cursor over restricted datesPrivate Sub CheckBox1_CheckedChanged(sender As System.Object, e As System.EventArgs) Handles CheckBox1.CheckedChanged
DateTimePickerEx1.ShowWeekNumbers = CheckBox1.Checked
End Sub
Dim tomorrow = Date.Today.AddDays(1)
With DateTimePickerEx1
.Value = tomorrow
.RestrictBefore(tomorrow)
.NoToday = True
.RestrictedDaysOfWeek.AddRange({DayOfWeek.Saturday, DayOfWeek.Sunday})
End With
Jquery
$("#datepicker").datepicke
or use CSS
/* Hide all weekend options in the jQueryUI DatePicker dialog */
th.ui-datepicker-week-end,
td.ui-datepicker-week-end {
display: none;
}
Holidays are a bit trickier as you have to define them
https://stackoverflow.com/questions/2029626/jquery-datepicker-disable-weekends-holidays-and-the-next-three-working-days