DateTimePicker?

How can I gray out or disable non weekdays (Sat, Sun) from the DateTimePicker?
LVL 1
Jess31Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

David Johnson, CD, MVPOwnerCommented:
You can make them non clickable
Jquery
$("#datepicker").datepicker({ beforeShowDay: $.datepicker.noWeekends });

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
0
Éric MoreauSenior .Net ConsultantCommented:
Windows Forms or WPF or ...?

If it is for WPF, have a look at http://emoreau.com/Entries/Articles/2015/09/Customizing-the-WPF-Calendar-control-.aspx
0
Jess31Author Commented:
I am only familiar with vb.net. I am not sure how to convert this to vb.net.
0
Build an E-Commerce Site with Angular 5

Learn how to build an E-Commerce site with Angular 5, a JavaScript framework used by developers to build web, desktop, and mobile applications.

Éric MoreauSenior .Net ConsultantCommented:
the very first question before starting to convert code is which platform are you targeting? If you have a Windows Form, the code above won't work since it is only for web!
0
Jess31Author Commented:
vb.net / winform
0
Éric MoreauSenior .Net ConsultantCommented:
I would go with a 3rd party control (telerik, devexpress)

you could also use the WPF control and host it on your Winform: http://emoreau.com/Entries/Articles/2014/05/Hosting-WPF-controls-on-a-Windows-Form.aspx
0
ArkCommented:
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

Open in new window

1
Jess31Author Commented:
Ark,
How would I use this DateTimePickerEx on a form ?
0
ArkCommented:
1. Add DateTimePickerEx class to project
2. Compile project (Menu->Build->Rebuild YourProjectName)
3. Open any form in designer - you'll see DateTimePickerEx control in toolbox
0
Jess31Author Commented:
Thanks.
Very cool!
0
ArkCommented:
A bit improved class:  
Futures:
1. Custom Back/Fore color for restricted  dates (either design or run time)
2. 3 collections and 2 Subs for restricted dates
'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))

Open in new window

3. Showing "No" cursor over restricted dates
4. Clicking on restricted dates have no effect.
DateTimePickerEx.zip
0
Jess31Author Commented:
DateTimePIckerEx1.MinDate is not suppose work ?
0
ArkCommented:
DateTimePickerEx is a Type (Class Name). DateTimePickerEx1 is an instance (control name on your form). When you drop control from toolbox on your form IDE name it as TypeName1 (TypeName2 for second etc). For example, if you drop Button its default name would be Button1. You can change control name in Properties window. In that case replace DateTimePickerEx1 with new name. Some properties you can set at design time in properties window. There are all properties from standard DateTimePicker plus new from DateTimePickerEx (RestrictedDaysOfWeek, RestrictedDates, RestrictedColors etc).
A bit more fun with Calendar styles (via properties):
- NoToday (hide "Today" link at the bottom of calendar)
- NoTodayCircle (no highlight for today date)
- NoTrailingDays (hide dates form previous and next month)
- ShowWeekNumbers (show week numbers on the left side of calendar)
DateTimePickerEx.zip
0
ArkCommented:
PS. You can set properties at design time or any time during runtime. For example, you can add checkbox with text "Show week numbers" and set appropriate property on it CheckedChange event:
Private Sub CheckBox1_CheckedChanged(sender As System.Object, e As System.EventArgs) Handles CheckBox1.CheckedChanged
    DateTimePickerEx1.ShowWeekNumbers = CheckBox1.Checked
End Sub

Open in new window

0
Jess31Author Commented:
But when I set
DateTimePickerExxx.MinDate = DateAdd(DateInterval.Day, 1, Now())
in runtime, and then when I click on the control I get an error
{"Year, Month, and Day parameters describe an un-representable DateTime."}
and it points to this
 Public Function ToDate() As DateTime
            Return New DateTime(Year, Month, Day)
        End Function
0
Jess31Author Commented:
In the last ver you posted it doesn't happen when clicking on the control but when you press on the right arrow (=next month) I get this error:

{"Value of '3/22/2017 11:23:18 PM' is not valid for 'Value'. 'Value' should be between 'MinDate' and 'MaxDate'." & vbCrLf & "Parameter name: Value"}
0
ArkCommented:
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Jess31Author Commented:
:) This one is charm. Thanks
0
ArkCommented:
BTW, you can restrict dates before tomorrow instead of setting MinDate :
Dim tomorrow = Date.Today.AddDays(1)
With DateTimePickerEx1
    .Value = tomorrow
    .RestrictBefore(tomorrow)
    .NoToday = True
    .RestrictedDaysOfWeek.AddRange({DayOfWeek.Saturday, DayOfWeek.Sunday})
End With

Open in new window

0
Jess31Author Commented:
yeah, this is much nicer. Thanks.
0
ArkCommented:
A few more futures:
1. Transparent "No" cursor (standard "No" cursor have non-transparent white area inside circle)
2. Customizable RestrictedFont property (you can set it different from standard, ie bold/italic/strikethru etc)
3. Customizable Prompt property (display text over DateTimePicker text area if invalid date selected by typing in text area)
DateTimePickerEx.zip
1
Jess31Author Commented:
with this new update I get errors on
.BorderStyle = Windows.Forms.BorderStyle.None,
says Forms is not a member of Windows.

Does something have to be added for this to work?
0
ArkCommented:
change to fully qualified assembly
.BorderStyle =System.Windows.Forms.BorderStyle.None
1
Éric MoreauSenior .Net ConsultantCommented:
solution provided
1
Éric MoreauSenior .Net ConsultantCommented:
Ark, do you happen to have the C# version of that class?
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.