TimeEdit Controls
TimeEdit, TimeCombo, TimeColumn for flexible time editing
Introduction
Similar Controls
System.Windows.Forms.DateTimePicker
- gTimePicker
How This Control Differs
Features comparison:
DateTimePicker | gTimePicker | TimeEdit | |
Value Update | On Mask complete On Lost focus On validated | On Lost focus On validated | Immediately after key press |
Text and Value is always the same | No | No | Yes |
Null Value Support | No | Yes | Yes |
could have time only value: like 0001/01/01 01:00 | No | Yes | Yes |
Has a dropdown clock | No | Yes | In TimeCombo |
It is not needed to use : or arrows when entering time | No | No | Yes |
Value after key press:
DateTimePicker | gTimePicker | TimeEdit | |
Example displayed Text | 00:00 | 00:00 | 00:00 |
Displayed text after pressing [6] Key | 6:00 | 60:00 | 06:00 |
Value after pressing [6] Key | 00:00 + current date | 00:00 | 06:00 |
Value after lost focus | 06:00 + current date | 06:00 | 06:00 |
Why I Decided to Create It
I need a control that has the following features:
Value
property can be set to time only value such as 00:00 (0001/01/01 00:00) witch is the minimum value for DateTime TypeValue
property can beDBNull.Value
and this is useful for database binding- Edit time that always its value reflect the displayed text
- Simple time entering by minimum typing
- Could the increase or decrease its value by mouse weal moving or by arrows pressing
Value Related Property of this Control
Value
(Object):DBNull
orWorkingDayDate
andTime
NullableDateTime
(Nullable(ofDateTime
)): Nothing orWorkingDayDate
andTime
NullableTime
(Nullable(ofDateTime
)): Nothing orTime
What This Application Does and Why it is Useful
You could include this control in your application to get the following features:
- Allows your application user to enter a time in 24 hour or 12 hour mode
- Protects your application user from entering invalid time
- If your application checks the value of this control, it will always return the right value even before the control lost focus and this is useful to get the value changing as user typing
- You could assign
TimeEdit
control with aWorkingDayDateControl
to return a date and time in a single property - It is a simple control and it is inherits from a
TextBox
and is easy to understand and could be devolved to another more complex control - It is an alternative and more useable than
DateTimePicker
What Problem is Solved
- When user changes the text of
TimeEdit
control, its value changes immediately even if it does not lose focus. TimeEdit
control does not have aMinValue
so it could point to time only value.- It has a
WorkingDayEndTime
andWorkingDayDate
property that is useful when used in appointment arrangement in a working day that continues after midnight - It could be assigned to
WorkingDayDateControl
to get the date part from it and return the date and time in a singleValue
property
About TimeCombo and TimeColumn
TimeCombo
is combo box based onTimeEdit
TimeCombo
uses Flexible ComboBox and EditingControl Library and gTimePicker ClockTimeColumn
isDataGridViewColumn
based onTimeCombo
and Flexible ComboBox and EditingControl Library
Globalization
This control will act the same even if your local culture is differ than en-US
. It always uses AM PM and : even if your local culture is use others.
What's the Next Step
- Add a drop down button to display a clock to select time
- Building an appointment grid to arrange appointments that could be continue after mid night without break sorting (00:00 will located after 23:59 when sorting by time
Using the Code
- You could
TimeEdit
control in your Windows application to mentioned time - If you build a user control, you could use
TimeConverter
andDateConverter
for your control property.
The Demo Application
The demo application comparing between DateTimePicker
and TimeEdit
control. There are 2 TimeEdit
controls, the first one has WorkingDayEndTime
property set to 00:00
and the second TimeEdit
control is WorkingDayEndTime
is set to 02:00
. When typing in any TimeEdit
control or in the DateTimePicker
control, the value of the control is shown the date of the second TimeEdit
control is set to 0001/01/02
(yyyy/MM/dd) if the time typed is less that WorkingDayEndTime
and this is useful when sorting time in an appointments arrangements.
It also contains DataGridView
that use TimeColumn
.
Points of Interest
How to Keep Value and Text the Same
To do so, we don't store the value in a separate variable. We use the displayed text to get the value. and when user sets the value programmatically, this control will study the value:
- If new value is numeric, it will be considered as Hour; 6.5 will be converted to 06:30
- If new value is
DateTime
, then theWorkingDayDate
property will be set to the new value date and theNullableTime
property will be set to time part of the new value - If new value is empty
string
, then value will beDBNull
- If new value is
string
that contains time, then the value will return its value
Public Overridable Property Value As Object
Get
Try
If String.IsNullOrEmpty(MyBase.Text) Then
Return DBNull.Value
Else
Return Me.NullableDateAndTime.Value
End If
Catch ex As Exception
ErrMsg(ex)
Return DBNull.Value
End Try
End Get
Set(ByVal NewValue As Object)
Try
If IsNumeric(NewValue) Then
'Nothing = 00:00
'not include date
Me.NullableTime = (New Date).AddHours(CDbl(NewValue))
ElseIf IsDate(NewValue) Then
'Nothing = 00:00
'include date
Me.NullableDateAndTime = CDate(NewValue)
ElseIf IsDBNull(NewValue) OrElse NewValue Is Nothing Then
Me.Text = ""
ElseIf GetType(TimeSpan).IsAssignableFrom(NewValue.GetType) Then
'not include date
Me.NullableTime = New Date(CType(NewValue, TimeSpan).Ticks)
ElseIf GetType(String).IsAssignableFrom(NewValue.GetType) Then
If String.IsNullOrEmpty(CStr(NewValue)) Then
Me.Text = ""
Else
'don't include date
Me.NullableTime = ToDateTime(CStr(NewValue))
End If
Else
Me.Text = ""
End If
Catch ex As Exception
ErrMsg(ex)
End Try
End Set
End Property
Validate Time Input and Protecting User from Entering Invalid Time
- Overrides
Sub OnKeyPress
- If user presses a key in an empty
TimeEdit
control, then it will automatically assign with default value - Build
sText string
that echoes the user input resultDim sText = Me.Text Mid(sText, Me.SelectionStart + 1, 1) = e.KeyChar 'Replace the 2d char
- Test if the resulting text is valid
Time
using Regular Expressions taking"^(?<Hour>([0-1]\d|2[0-3])):(?<Minute>[0-5]\d)$"
for 24 hour mode and"^(?<Hour>(0?[1-9]|1[0-2])):(?<Minute>[0-5]\d) (?<AMPM>(A|P)M)$"
for 12 hour mode
* This Regular Expressions contains three groups: Hour, Minute and AMPM
* Each group has its rule example Hour in 12 hour mode is 0 followed by any digest or 1 followed by 0-2 - If not match, then study where the editing
char
in hours or in minutes and study its possible fixing as the following code:Private Sub OnHourKeyPress(ByRef e As KeyPressEventArgs) Try Dim Do1 = False Select Case SelectionStart Case 0 'SelectionStart = 0 Select Case e.KeyChar Case "3"c To "9"c 'not allowed to be first char Do1 = True Case "2"c 'not allowed to be first char in 12 Hr mode If Not _Hr24 Then Do1 = True Else 'in 24 hr mode if the next char is > 3 then replace it with 3 If Me.Text()(1) > "3"c Then Mid(Me.Text, 2, 1) = "3" End If End If Case "1"c If Not _Hr24 Then 'in 12 hr mode if the next char is > 2 then replace it with 2 If Me.Text()(1) > "2"c Then Mid(Me.Text, 2, 1) = "2" End If End If End Select Case 1 'SelectionStart = 1 Select Case MyBase.Text(0) Case Is > "2"c 'in 12 hr mode not allowed to be in 2d char If Not Hr24 Then Do1 = True End If Case "2"c If Me.Hr24 Then Select Case e.KeyChar Case "4"c To "9"c 'in 24 hr mode not allowed to be in 2d char Do1 = True End Select Else Do1 = True End If Case "1"c If Not _Hr24 Then Select Case e.KeyChar Case "3"c To "9"c Do1 = True End Select End If End Select 'MyBase.Text(0) End Select If Do1 Then Me.Text = "0" & Me.Text.Substring(1) SelectionStart = 1 SelectionLength = 1 End If OnTimeKeyPress(e) Catch ex As Exception ErrMsg(ex) End Try End Sub
TimeEdit
control Inherits TextBox
but it removes some properties by:
- Adding
Designer
attribute:<ToolboxItem(True), Designer(GetType(TimeEditDesigner)), _ DefaultBindingProperty("Value")> _ Public Class TimeEdit Inherits TextBox '....More Code.... <DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), _ Browsable(False), Obsolete("", True)> _ Public Shadows Lines, Multiline, AutoCompleteMode, _ AutoCompleteSource, AutoCompleteCustomSource, WordWrap, _ PasswordChar, UseSystemPasswordChar As DBNull End Class
- Building
TimeEditDesigner
class:Imports System.Windows.Forms.Design Imports System.ComponentModel Public Class TimeEditDesigner Inherits ControlDesigner Protected Overrides Sub PreFilterProperties(ByVal properties As IDictionary) Try properties.Remove("PasswordChar") properties.Remove("UseSystemPasswordChar") properties.Remove("Text") properties.Remove("Lines") properties.Remove("Multiline") properties.Remove("AutoCompleteMode") properties.Remove("AutoCompleteSource") properties.Remove("AutoCompleteCustomSource") properties.Remove("WordWrap") MyBase.PreFilterProperties(properties) Catch ex As Exception ErrMsg(ex) End Try End Sub Public Overrides ReadOnly Property ActionLists As _ System.ComponentModel.Design.DesignerActionListCollection Get Return Nothing End Get End Property Public Overrides ReadOnly Property Verbs As _ System.ComponentModel.Design.DesignerVerbCollection Get Return Nothing End Get End Property End Class
How This Application Handles Run Time Errors
Every procedure has the following diagram:
Private Sub OnHourKeyPress(ByRef e As KeyPressEventArgs) 'procedure start
Try
'.... procedure code
Catch ex As Exception
ErrMsg(ex)
End Try
End Sub 'procedure end
A module that contains ErrMsg
procedure is added to the project to document every run time error that happened in a file located in "C:\Temp".
The error is printed to that file using as follows:
FileOpen(iFile, sLogFileName, OpenMode.Append, OpenAccess.Write)
Print(iFile, vbNewLine & vbNewLine & "Date: " _
& Now.ToString("yyyy/MM/dd HH:mm:ss") & vbNewLine)
Print(iFile, sMsg)
FileClose(iFile)
History
- Initial version
- Adding
TimeCombo
andTimeColumn