65.9K
CodeProject 正在变化。 阅读更多。
Home

TimeEdit 控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.60/5 (16投票s)

2011年8月11日

CPOL

5分钟阅读

viewsIcon

44275

downloadIcon

2832

TimeEdit、TimeCombo、TimeColumn,用于灵活的时间编辑

引言

类似控件

  1. System.Windows.Forms.DateTimePicker
  2. gTimePicker

此控件的区别

功能对比

  DateTimePicker gTimePicker TimeEdit
值更新 掩码完成时
失去焦点时
验证后
失去焦点时
验证后
按键后立即
文本和值是
始终相同
空值支持
可以只有时间值
例如 0001/01/01 01:00
有下拉时钟 TimeCombo 中 
输入时间时
不需要使用 : 或箭头

按键后的值

  DateTimePicker gTimePicker TimeEdit
显示的文本示例 00:00 00:00 00:00
按下 [6] 键后显示的文本 6:00 60:00 06:00
按下 [6] 键后的值 00:00 + 当前日期 00:00 06:00
失去焦点后的值 06:00 + 当前日期   06:00 06:00

我为何决定创建它

我需要一个具有以下功能的控件

  1. Value 属性可以设置为仅时间值,例如 00:00 (0001/01/01 00:00),这是 DateTime 类型的最小值
  2. Value 属性可以是 DBNull.Value,这对于数据库绑定很有用
  3. 编辑时间时,其值始终反映显示的文本
  4. 通过最少的输入进行简单的时间输入
  5. 可以使用鼠标滚轮或按下箭头键来增加或减少其值

与此控件相关的值属性

  1. Value                          (Object):                          DBNullWorkingDayDateTime
  2. NullableDateTime   (Nullable(of DateTime)): Nothing 或 WorkingDayDateTime
  3. NullableTime           (Nullable(of DateTime)): Nothing 或 Time

此应用程序的功能及其用途

您可以将此控件包含在您的应用程序中以获得以下功能

  1. 允许您的应用程序用户以 24 小时制或 12 小时制输入时间
  2. 保护您的应用程序用户免于输入无效时间
  3. 如果您的应用程序检查此控件的值,它将始终返回正确的值,即使在控件失去焦点之前,这对于在用户输入时获取值变化很有用
  4. 您可以将 TimeEdit 控件与 WorkingDayDateControl 关联,以便在一个属性中返回日期和时间
  5. 它是一个简单的控件,继承自 TextBox,易于理解,并且可以进一步开发为更复杂的控件
  6. 它是 DateTimePicker 的替代品,并且更易于使用

解决了什么问题

  1. 当用户更改 TimeEdit 控件的文本时,即使它没有失去焦点,其值也会立即更改。
  2. TimeEdit 控件没有 MinValue,因此它可以指向仅时间值。
  3. 它具有 WorkingDayEndTimeWorkingDayDate 属性,当在午夜后持续的工作日中安排约会时很有用
  4. 它可以分配给 WorkingDayDateControl 以从中获取日期部分,并在单个 Value 属性中返回日期和时间

关于 TimeCombo 和 TimeColumn

全球化

即使您的本地文化与 en-US 不同,此控件的行为也始终如一。它始终使用 AM/PM 和 :,即使您的本地文化使用其他格式。

下一步是什么

  1. 添加下拉按钮以显示时钟以选择时间
  2. 构建一个约会网格来安排可以跨越午夜而无需中断排序的约会(按时间排序时,00:00 会排在 23:59 之后)

Using the Code

  1. 您可以在您的 Windows 应用程序中使用 TimeEdit 控件来提及时间
  2. 如果您构建一个用户控件,您可以使用 TimeConverterDateConverter 来处理您的控件属性。

演示应用程序

演示应用程序比较了 DateTimePickerTimeEdit 控件。有两个 TimeEdit 控件,第一个控件的 WorkingDayEndTime 属性设置为 00:00,第二个 TimeEdit 控件的 WorkingDayEndTime 设置为 02:00。当在任何 TimeEdit 控件或 DateTimePicker 控件中键入时,控件的值将显示为日期。如果输入的时间小于 WorkingDayEndTime,则第二个 TimeEdit 控件的日期将设置为 0001/01/02 (yyyy/MM/dd),这在按时间对约会安排进行排序时非常有用。
它还包含使用 TimeColumnDataGridView

关注点

如何保持值和文本相同

为此,我们不将值存储在单独的变量中。我们使用显示的文本来获取值。当用户以编程方式设置值时,此控件将分析该值

  1. 如果新值是数字,则将其视为小时;6.5 将转换为 06:30
  2. 如果新值是 DateTime,则 WorkingDayDate 属性将设置为新值的日期,NullableTime 属性将设置为新值的时间部分
  3. 如果新值是空的 string,则值为 DBNull
  4. 如果新值是包含时间的 string,则值将返回其值
    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

验证时间输入并保护用户免于输入无效时间

  1. 重写 Sub OnKeyPress
  2. 如果用户在空的 TimeEdit 控件中按下某个键,它将自动分配默认值
  3. 构建 sText string 来反映用户输入的結果 
    Dim sText = Me.Text
    Mid(sText, Me.SelectionStart + 1, 1) = e.KeyChar 'Replace the 2d char
  4. 使用正则表达式测试结果文本是否为有效的 Time,24 小时制使用 "^(?<Hour>([0-1]\d|2[0-3])):(?<Minute>[0-5]\d)$",12 小时制使用 "^(?<Hour>(0?[1-9]|1[0-2])):(?<Minute>[0-5]\d) (?<AMPM>(A|P)M)$"
    * 此正则表达式包含三个组:小时、分钟和 AM/PM
    * 每个组都有其规则,例如 12 小时制中的小时是 0 后跟任意数字或 1 后跟 0-2  
  5. 如果不匹配,则分析编辑 char 在小时或分钟中的位置,并分析其可能的修复方法,如下面的代码所示: 
        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 控件继承自 TextBox,但通过以下方式移除了部分属性

  1. 添加 Designer 属性
    <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
  2. 构建 TimeEditDesigner
    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

此应用程序如何处理运行时错误

每个过程都包含以下图

Private Sub OnHourKeyPress(ByRef e As KeyPressEventArgs) 'procedure start
    Try
    
    '.... procedure code
  	Catch ex As Exception
		ErrMsg(ex)
    End Try
End Sub 'procedure end

向项目中添加了一个包含 ErrMsg 过程的模块,用于记录发生的所有运行时错误,文件位于“C:\Temp”。

错误使用如下方式打印到该文件

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)

历史

  • 初始版本
  • 添加 TimeComboTimeColumn
© . All rights reserved.