Search code examples
vb.netwinformsdatagridviewdatetimepickerdatetime-format

DataGridView DateTimePicker Column - add Long Format support (Date and the Time)


I'm trying to make gridview Datetimepicker column and i succeeded, but i have a little problem that when the user edit the date in the gridview the date appear in short "11/9/16" but what i want is the date and the time together"11/9/16 2:34:45 AM"

This is the code I use:

CalendarColumn:

Imports System
Imports System.Windows.Forms

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 (value IsNot 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

CalendarCell:

Public Class CalendarCell
Inherits DataGridViewTextBoxCell

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 CalendarEditingControl = _
        CType(DataGridView.EditingControl, CalendarEditingControl)

    ' Use the default row value when Value property is null.
    If (Me.Value Is Nothing) Then
        ctl.Value = CType(Me.DefaultNewRowValue, DateTime)
    Else
        ctl.Value = CType(Me.Value, DateTime)
    End If
End Sub

Public Overrides ReadOnly Property EditType() As Type
    Get
        ' Return the type of the editing control that CalendarCell uses.
        Return GetType(CalendarEditingControl)
    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 DefaultNewRowValue() As Object
    Get
        ' Use the current date and time as the default value.
        Return DateTime.Now
    End Get
End Property

End Class

CalendarEditingControl:

Class CalendarEditingControl
Inherits DateTimePicker
Implements IDataGridViewEditingControl

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

Public Sub New()
     Me.Format = DateTimePickerFormat.Long
    'Me.CustomFormat = "'Today is:' hh:mm:ss dddd MMMM dd, yyyy"
End Sub

Public Property EditingControlFormattedValue() As Object _
    Implements IDataGridViewEditingControl.EditingControlFormattedValue

    Get
        Return Me.Value.ToShortDateString()
    End Get

    Set(ByVal value As Object)
        Try
            ' This will throw an exception of the string is 
            ' null, empty, or not in the format of a date.
            Me.Value = DateTime.Parse(CStr(value))
        Catch
            ' In the case of an exception, just use the default
            ' value so we're not left with a null value.
            Me.Value = DateTime.Now
        End Try
    End Set

End Property

Public Function GetEditingControlFormattedValue(ByVal context _
    As DataGridViewDataErrorContexts) As Object _
    Implements IDataGridViewEditingControl.GetEditingControlFormattedValue

    Return Me.Value.ToShortDateString()

End Function

Public Sub ApplyCellStyleToEditingControl(ByVal dataGridViewCellStyle As _
    DataGridViewCellStyle) _
    Implements IDataGridViewEditingControl.ApplyCellStyleToEditingControl

    Me.Font = dataGridViewCellStyle.Font
    Me.CalendarForeColor = dataGridViewCellStyle.ForeColor
    Me.CalendarMonthBackground = dataGridViewCellStyle.BackColor

End Sub

And this code for add column :

Dim col As New CalendarColumn() With {.HeaderText = "Date time"}
DataGridView1.Columns.Insert(5, col)

source Code

How can I make it long with the time.


Solution

  • To show a date and time in custom format, you should assign format to Format property of DefaultCellStyle. The CustomFormat property of DateTimePicker is useful for editing format but for displaying data in cell you should use column.DefaultCellStyle.Format.

    For example to show date and time like 2016/09/15 10:31:04 PM you should use yyyy/MM/dd h:mm:ss tt as format.

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim dt = New DataTable()
        dt.Columns.Add("Date", GetType(DateTime))
        dt.Rows.Add(DateTime.Now)
        dt.Rows.Add(DateTime.Now)
        Dim column = New DataGridViewTextBoxColumn()
        column.DefaultCellStyle.Format = "yyyy/MM/dd h:mm:ss tt"
        column.DataPropertyName = "Date"
        Me.DataGridView1.Columns.Add(column)
        Me.DataGridView1.DataSource = dt
    End Sub
    

    For more information about custom date formats see:


    DataGridView DateTimePicker Column

    Here is the full source code of date time picker column with some fixes. The source has been taken from MSDN and I just made some small changes and a small fix. The changes has been made to support Time and long format. Also the fix has been done to prevent exception when the cell value is DBNull.Value:

    Imports System
    Imports System.Windows.Forms
    
    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 (value IsNot 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
    
        Public Sub New()
            ' Use the short date format.
            Me.Style.Format = "yyyy/MM/dd h:mm:ss tt"
        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 CalendarEditingControl = _
                CType(DataGridView.EditingControl, CalendarEditingControl)
    
            ' Use the default row value when Value property is null.
            If (Me.Value Is Nothing OrElse IsDBNull(Me.Value)) Then
                ctl.Value = CType(Me.DefaultNewRowValue, DateTime)
            Else
                ctl.Value = CType(Me.Value, DateTime)
            End If
        End Sub
    
        Public Overrides ReadOnly Property EditType() As Type
            Get
                ' Return the type of the editing control that CalendarCell uses.
                Return GetType(CalendarEditingControl)
            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 DefaultNewRowValue() As Object
            Get
                ' Use the current date and time as the default value.
                Return DateTime.Now
            End Get
        End Property
    
    End Class
    
    Class CalendarEditingControl
        Inherits DateTimePicker
        Implements IDataGridViewEditingControl
    
        Private dataGridViewControl As DataGridView
        Private valueIsChanged As Boolean = False
        Private rowIndexNum As Integer
    
        Public Sub New()
            Me.Format = DateTimePickerFormat.Custom
            Me.CustomFormat = "yyyy/MM/dd h:mm:ss tt"
        End Sub
    
        Public Property EditingControlFormattedValue() As Object _
            Implements IDataGridViewEditingControl.EditingControlFormattedValue
    
            Get
                Return Me.Value.ToString("yyyy/MM/dd h:mm:ss tt")
            End Get
    
            Set(ByVal value As Object)
                Try
                    ' This will throw an exception of the string is 
                    ' null, empty, or not in the format of a date.
                    Me.Value = DateTime.Parse(CStr(value))
                Catch
                    ' In the case of an exception, just use the default
                    ' value so we're not left with a null value.
                    Me.Value = DateTime.Now
                End Try
            End Set
    
        End Property
    
        Public Function GetEditingControlFormattedValue(ByVal context _
            As DataGridViewDataErrorContexts) As Object _
            Implements IDataGridViewEditingControl.GetEditingControlFormattedValue
    
            Return Me.Value.ToString("yyyy/MM/dd h:mm:ss tt")
    
        End Function
    
        Public Sub ApplyCellStyleToEditingControl(ByVal dataGridViewCellStyle As  _
            DataGridViewCellStyle) _
            Implements IDataGridViewEditingControl.ApplyCellStyleToEditingControl
    
            Me.Font = dataGridViewCellStyle.Font
            Me.CalendarForeColor = dataGridViewCellStyle.ForeColor
            Me.CalendarMonthBackground = dataGridViewCellStyle.BackColor
    
        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
    
                    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 Class
    

    And here is the test code:

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim dt = New DataTable()
        dt.Columns.Add("Date", GetType(DateTime))
        dt.Rows.Add(DateTime.Now)
        dt.Rows.Add(DateTime.Now)
        Dim column = New CalendarColumn()
        column.DataPropertyName = "Date"
        Me.DataGridView1.Columns.Add(column)
        Me.DataGridView1.DataSource = dt
    End Sub