?
Solved

DateTimePicker and Bound DataGridView

Posted on 2012-09-06
6
Medium Priority
?
1,367 Views
Last Modified: 2012-09-11
Hi,

I know this has been asked before but I can't seem to understand how to apply the following code to a bound column in my current datagridview : http://msdn.microsoft.com/en-us/library/7tas5c80.aspx

The article seems to create a datagridview from scratch and then add a new column to it which will have the dateTimePicker, but how can I convert one of my existing columns to a dateTimePicker?

My current datagridview is bound to a bindingsource connected to an access database; I have a date column which I would like to give the user the option of picking a date through the dateTimePicker when he clicks on a cell in the column.

Thank you for your help!
0
Comment
Question by:FCapo
  • 3
  • 2
6 Comments
 
LVL 83

Expert Comment

by:CodeCruiser
ID: 38373339
There is no DateTimePicker column built in so you have to create your own as shown in that link.
0
 
LVL 28

Expert Comment

by:Ark
ID: 38382460
Furthermore, DateTimePicker is not nullable, so you have to create your own DB_DatePicker control first which accepts DBNULL value
0
 
LVL 28

Accepted Solution

by:
Ark earned 2000 total points
ID: 38382481
    <ToolboxItem(True), ToolboxBitmap(GetType(Windows.Forms.DateTimePicker))> _
    Public Class DB_DatePicker
        Inherits System.Windows.Forms.DateTimePicker
        Implements INotifyPropertyChanged

        Private _nullValueText As String = "Not set"
        Private _dateSelected As Object = System.DBNull.Value
        Private _TextBox As TextBox
        Private _panel As Panel
        Private bFromCode As Boolean
        'Public Event SelectedValueChanged As EventHandler
        Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

#Region " Constructor/Destructor "
        Public Sub New()
            MyBase.New()
            _TextBox = New TextBox
            _panel = New Panel
            InitializeComponent()
        End Sub
        Protected Overrides Sub Dispose(ByVal disposing As Boolean)
            Try
                RemoveHandler _TextBox.MouseDown, AddressOf txt_MouseDown
                _TextBox.Dispose()
                _panel.Dispose()
            Finally
                MyBase.Dispose(disposing)
            End Try
        End Sub
        Private Sub InitializeComponent()
            Me.SuspendLayout()
            Me.Name = "NullableDTP"
            Me.Size = New System.Drawing.Size(186, 69)

            With _TextBox
                .TabStop = False
                .TabIndex = Me.TabIndex
                .BackColor = Me.BackColor
                .ForeColor = Color.Gray 'Me.ForeColor
                .BorderStyle = Windows.Forms.BorderStyle.None
                .Location = New Point(3, 3)
                .Dock = DockStyle.Fill
                .Text = _nullValueText
            End With
            AddHandler _TextBox.MouseDown, AddressOf txt_MouseDown
            With _panel
                .BackColor = Me.BackColor
                .TabStop = False
                .TabIndex = Me.TabIndex
                .BorderStyle = Windows.Forms.BorderStyle.None
                .Location = New Point(1, 1)
                .Size = New Size((Me.Width - SystemInformation.VerticalScrollBarWidth - 6), Me.Height - 2)
                .Controls.Add(_TextBox)
            End With
            Me.Controls.Add(_panel)
            _dateSelected = DBNull.Value
            Me.ResumeLayout(False)
        End Sub
#End Region

#Region " API Calls "
        Private Const DTM_GETMONTHCAL As Integer = &H1008
        Private Const MCM_SETCURSEL As Integer = &H1002
        Private Declare Auto Function SendMessage Lib "user32.dll" (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As IntPtr, ByVal lParam As SystemTime) As IntPtr
        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

        <System.Runtime.InteropServices.StructLayout(Runtime.InteropServices.LayoutKind.Sequential)> _
        Private Class SystemTime
            Public wYear As Short
            Public wMonth As Short
            Public wDayOfWeek As Short
            Public wDay As Short
            Public wHour As Short
            Public wMinute As Short
            Public wSecond As Short
            Public wMilliseconds As Short
        End Class
        Private Function DateTimeToSysTime(ByVal time As DateTime) As SystemTime
            Dim sysTime As New SystemTime
            With sysTime
                .wYear = CShort(time.Year)
                .wMonth = CShort(time.Month)
                .wDayOfWeek = CShort(time.DayOfWeek)
                .wDay = CShort(time.Day)
                .wHour = CShort(time.Hour)
                .wMinute = CShort(time.Minute)
                .wSecond = CShort(time.Second)
                .wMilliseconds = 0
            End With
            Return sysTime
        End Function
#End Region

#Region " Properties "
        <Bindable(True), Browsable(False)> _
        Public Property SelectedValue() As Object
            Get
                Return _dateSelected
            End Get
            Set(ByVal value As Object)
                If bFromCode Then Return
                Dim dt As Date
                If value Is DBNull.Value OrElse value Is Nothing Then
                    Me.Value = Me.MinDate.Date
                Else
                    If Date.TryParse(value.ToString, dt) Then
                        Me.Value = dt.Date
                    Else
                        Me.Value = Me.MinDate.Date
                    End If
                End If
            End Set
        End Property
        <DefaultValue("¿¿ ¿¿¿¿¿¿¿")> _
            Public Property NullValueText() As String
            Get
                Return _nullValueText
            End Get
            Set(ByVal value As String)
                _nullValueText = value
                _TextBox.Text = NullValueText
            End Set
        End Property
        Public ReadOnly Property EditControl() As TextBox
            Get
                Return _TextBox
            End Get
        End Property
#End Region

#Region " Control's events "
        Private Sub DB_DatePicker_DropDown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.DropDown
            If Me.Value = Me.MinDate Then
                Dim hMonth As IntPtr = SendMessage(Me.Handle, DTM_GETMONTHCAL, IntPtr.Zero, IntPtr.Zero)
                If hMonth <> IntPtr.Zero Then
                    Dim t As SystemTime = DateTimeToSysTime(Date.Now)
                    SendMessage(hMonth, MCM_SETCURSEL, IntPtr.Zero, t)
                End If
            End If
        End Sub

        Private Sub DB_DatePicker_Enter(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Enter
            If bFromCode Then Return
            bFromCode = True
            'Me.RecreateHandle()
            bFromCode = False
        End Sub

        Private Sub DB_DatePicker_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.GotFocus
            If Me.Value = Me.MinDate Then Me.Value = Date.Today
            _panel.Visible = False
        End Sub

        Private Sub DB_DatePicker_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
            Select Case e.KeyCode
                Case Keys.Delete
                    e.Handled = True
                    Me.Value = Me.MinDate
                Case Keys.Enter
                    e.Handled = True
                    If _dateSelected Is DBNull.Value Then _dateSelected = Me.Value
                    SendKeys.Send(vbTab)
                Case Else
            End Select
        End Sub

        Private Sub DB_DatePicker_Leave(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Leave
            If _dateSelected Is DBNull.Value Then
                Me.Value = Me.MinDate
                _panel.Visible = True
            End If
        End Sub
        Private Sub DB_DatePicker_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
            _panel.Size = New Size((Me.Width - SystemInformation.VerticalScrollBarWidth - 6), Me.Height - 2)
        End Sub
        Private Sub DB_DatePicker_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.ValueChanged
            If bFromCode Then Return
            If Me.Value.Date > Me.MinDate.Date Then
                If IsDBNull(_dateSelected) OrElse Not Me.Value.Date.Equals(_dateSelected) Then
                    _dateSelected = Me.Value.Date
                    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("SelectedValue"))
                End If
            Else
                If Not IsDBNull(_dateSelected) Then
                    _dateSelected = System.DBNull.Value
                    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("SelectedValue"))
                End If
            End If
            _panel.Visible = _dateSelected Is DBNull.Value
        End Sub
        Private Sub txt_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
            Me.Select()
        End Sub

#End Region

    End Class

    Public Class CalendarColumn
        Inherits DataGridViewColumn

        Public Sub New()
            MyBase.New(New CalendarCell())
        End Sub

        Public Overrides Property CellTemplate() As DataGridViewCell
            Get
                Return MyBase.CellTemplate
            End Get
            Set(ByVal value As DataGridViewCell)

                ' Ensure that the cell used for the template is a CalendarCell.
                If Not (value Is Nothing) AndAlso _
                    Not value.GetType().IsAssignableFrom(GetType(CalendarCell)) _
                    Then
                    Throw New InvalidCastException("Must be a CalendarCell")
                End If
                MyBase.CellTemplate = value
            End Set
        End Property

    End Class
    Public Class CalendarCell
        Inherits DataGridViewTextBoxCell
        Dim strNullText As String

        Public Sub New()
            ' Use the short date format.
            Me.Style.Format = "d"
        End Sub

        Public Overrides Sub InitializeEditingControl(ByVal rowIndex As Integer, _
            ByVal initialFormattedValue As Object, _
            ByVal dataGridViewCellStyle As DataGridViewCellStyle)

            ' Set the value of the editing control to the current cell value.
            MyBase.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle)

            Dim ctl As NullableDBPicker = CType(DataGridView.EditingControl, NullableDBPicker)
            strNullText = ctl.NullValueText
            If Me.RowIndex < 0 Then Return
            If Me.Value Is DBNull.Value Then
                ctl.Value = ctl.MinDate
            Else
                ctl.Value = CDate(Me.Value)
            End If
        End Sub
        Public Overrides ReadOnly Property EditType() As Type
            Get
                ' Return the type of the editing contol that CalendarCell uses.
                Return GetType(NullableDBPicker)
            End Get
        End Property
        Public Overrides ReadOnly Property ValueType() As Type
            Get
                ' Return the type of the value that CalendarCell contains.
                Return GetType(DateTime?)
            End Get
        End Property
        Public Overrides ReadOnly Property FormattedValueType() As Type
            Get
                ' Return the type of the value that CalendarCell contains.
                Return GetType(String)
            End Get
        End Property
        Public Overrides ReadOnly Property DefaultNewRowValue() As Object
            Get
                Return DBNull.Value
            End Get
        End Property
        Protected Overrides Function GetFormattedValue(ByVal value As Object, ByVal rowIndex As Integer, ByRef cellStyle As System.Windows.Forms.DataGridViewCellStyle, ByVal valueTypeConverter As System.ComponentModel.TypeConverter, ByVal formattedValueTypeConverter As System.ComponentModel.TypeConverter, ByVal context As System.Windows.Forms.DataGridViewDataErrorContexts) As Object
            Dim dt As Date
            If strNullText Is Nothing Then
                Dim ctl As New DB_DatePicker
                strNullText = ctl.NullValueText
                ctl.Dispose()
            End If
            Dim formattedValue As Object = MyBase.GetFormattedValue(value, rowIndex, cellStyle, valueTypeConverter, formattedValueTypeConverter, context)
            Dim formattedDate As String = formattedValue.ToString
            If value Is DBNull.Value Then
                Return strNullText
            Else
                If DateTime.TryParse(formattedDate, dt) Then
                    Return dt.ToShortDateString
                Else
                    Return strNullText
                End If
            End If
        End Function
        Public Overrides Function ParseFormattedValue(ByVal formattedValue As Object, ByVal cellStyle As System.Windows.Forms.DataGridViewCellStyle, ByVal formattedValueTypeConverter As System.ComponentModel.TypeConverter, ByVal valueTypeConverter As System.ComponentModel.TypeConverter) As Object
            Dim dt As Date
            If TypeOf formattedValue Is String Then
                If DateTime.TryParse(CStr(formattedValue), dt) Then
                    Return dt
                End If
            End If
            Return DBNull.Value
        End Function

    End Class
    Class NullableDBPicker
        Inherits DB_DatePicker
        Implements IDataGridViewEditingControl

        Private dataGridViewControl As DataGridView
        Private valueIsChanged As Boolean = False
        Private rowIndexNum As Integer

        Public Sub New()
            'Me.NullValueText = "¿¿ ¿¿¿¿¿¿¿"
            Me.Format = DateTimePickerFormat.Short
        End Sub

#Region " Implementation "
        Public Property EditingControlFormattedValue() As Object _
            Implements IDataGridViewEditingControl.EditingControlFormattedValue
            Get
                If Me.Value = Me.MinDate Then
                    Return Me.NullValueText
                Else
                    Return Me.Value.ToShortDateString
                End If
            End Get
            Set(ByVal value As Object)
                Dim dt As Date
                If TypeOf value Is String Then
                    If Date.TryParse(value.ToString, dt) Then
                        Me.Value = dt.Date
                    Else
                        Me.Value = Me.MinDate.Date
                    End If
                Else
                    Me.Value = Me.MinDate.Date
                End If
            End Set
        End Property
        Public Function GetEditingControlFormattedValue(ByVal context _
            As DataGridViewDataErrorContexts) As Object _
            Implements IDataGridViewEditingControl.GetEditingControlFormattedValue
            Return EditingControlFormattedValue
        End Function
        Public Sub ApplyCellStyleToEditingControl(ByVal dataGridViewCellStyle As  _
            DataGridViewCellStyle) _
            Implements IDataGridViewEditingControl.ApplyCellStyleToEditingControl

            Me.Font = dataGridViewCellStyle.Font
        End Sub
        Public Property EditingControlRowIndex() As Integer _
            Implements IDataGridViewEditingControl.EditingControlRowIndex
            Get
                Return rowIndexNum
            End Get
            Set(ByVal value As Integer)
                rowIndexNum = value
            End Set
        End Property
        Public Function EditingControlWantsInputKey(ByVal key As Keys, _
            ByVal dataGridViewWantsInputKey As Boolean) As Boolean _
            Implements IDataGridViewEditingControl.EditingControlWantsInputKey
            ' Let the DateTimePicker handle the keys listed.
            Select Case key And Keys.KeyCode
                Case Keys.Left, Keys.Up, Keys.Down, Keys.Right, _
                    Keys.Home, Keys.End, Keys.PageDown, Keys.PageUp, Keys.Delete

                    Return True

                Case Else
                    Return Not dataGridViewWantsInputKey
            End Select
        End Function
        Public Sub PrepareEditingControlForEdit(ByVal selectAll As Boolean) _
            Implements IDataGridViewEditingControl.PrepareEditingControlForEdit
            ' No preparation needs to be done.
        End Sub
        Public ReadOnly Property RepositionEditingControlOnValueChange() _
            As Boolean Implements _
            IDataGridViewEditingControl.RepositionEditingControlOnValueChange
            Get
                Return False
            End Get
        End Property
        Public Property EditingControlDataGridView() As DataGridView _
            Implements IDataGridViewEditingControl.EditingControlDataGridView
            Get
                Return dataGridViewControl
            End Get
            Set(ByVal value As DataGridView)
                dataGridViewControl = value
            End Set
        End Property
        Public Property EditingControlValueChanged() As Boolean _
            Implements IDataGridViewEditingControl.EditingControlValueChanged
            Get
                Return valueIsChanged
            End Get
            Set(ByVal value As Boolean)
                valueIsChanged = value
            End Set
        End Property
        Public ReadOnly Property EditingControlCursor() As Cursor _
            Implements IDataGridViewEditingControl.EditingPanelCursor
            Get
                Return MyBase.Cursor
            End Get
        End Property
        Protected Overrides Sub OnValueChanged(ByVal eventargs As EventArgs)
            ' Notify the DataGridView that the contents of the cell have changed.
            valueIsChanged = True
            Me.EditingControlDataGridView.NotifyCurrentCellDirty(True)
            MyBase.OnValueChanged(eventargs)
        End Sub
#End Region
    End Class

Open in new window

0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 

Author Comment

by:FCapo
ID: 38384340
Yes but I don't understand from the code how I can convert an existing databound column to use the dateTimePicker
0
 
LVL 28

Expert Comment

by:Ark
ID: 38385533
Place code into new class module in your project. Compile project (run it). Next time you'll edit column type in datagridview you'll see 'CalendarColumn' along with 'standard' column types (text,combo etc). Or, alternate, replace columntype in yourForm.designer.vb manually with fully qualified assembly name of CalendarColumn, like yourAssyNamespace.Classname.CalendarColumn
0
 

Author Comment

by:FCapo
ID: 38387036
Ok great,

I'm generating this manually through the code on my form, connecting to database;filling dataset, creating bindingsource, linking to datagridview.

The issue now is how can I set the column type to be CalendarColumn.

I know the CalendarColumn appears as a choice if I add the column through the designer part of my form, but what if I'm doing this through code, basically everything is done at runtime?

Can I change the column type of an existing column? When my form loads this is the code :
        
cliBindingSource = New BindingSource

With cliBindingSource
            .DataSource = cliDataSet
            .DataMember = "DataTable"
            .Sort = "sName"
        End With
        DataGridView1.DataSource = cliBindingSource

Open in new window

0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A while ago, I was working on a Windows Forms application and I needed a special label control with reflection (glass) effect to show some titles in a stylish way. I've always enjoyed working with graphics, but it's never too clever to re-invent …
Parsing a CSV file is a task that we are confronted with regularly, and although there are a vast number of means to do this, as a newbie, the field can be confusing and the tools can seem complex. A simple solution to parsing a customized CSV fi…
Screencast - Getting to Know the Pipeline
Is your OST file inaccessible, Need to transfer OST file from one computer to another? Want to convert OST file to PST? If the answer to any of the above question is yes, then look no further. With the help of Stellar OST to PST Converter, you can e…
Suggested Courses
Course of the Month17 days, 5 hours left to enroll

862 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question