易于编写和使用的可为空的 DateTimePicker






4.55/5 (15投票s)
使用 Visual Studio 2008,可以轻松创建 Microsoft 的 DateTimePicker 的可空版本。
引言
还是老一套:我需要一个可以显示空白值的日期时间选择器,并且我不想培训我的用户,让他们知道一个灰色的日期,并且没有选中复选框实际上意味着没有日期。 在浏览了 CodeProject 上的许多控件后,我感到有些沮丧。 我尝试使用 VB 和 Visual Studio 2008 制作自己的版本,并且在没有做很多工作的情况下,我得到了一些我喜欢的东西。
使用代码
基本控件本身非常简单:一个包含 MaskedEditBox
和 Panel
的 UserControl
。 MaskedEditBox
被屏蔽为短日期格式,用户可以输入日期或清除控件。停靠在 MaskedEditBox
内部右边缘的是一个充当按钮的 Panel
控件。 如果用户单击它,则会弹出一个 VS 2008 MonthCalendar
控件的扩展版本。 如果 MaskedEditBox
有一个日期,则该日期将在弹出窗口中预先选择。 选择一个日期会将该日期复制到 MaskedEditBox
中,或者用户可以单击“清除日期”按钮来清除 MaskedEditBox
。 任何一种选择都会关闭弹出窗口。 用户还可以选择通过单击“关闭”按钮来关闭弹出窗口,而不更改日期。
定义弹出窗口的代码作为私有类嵌入在控件中。 编写它非常简单:我创建了一个常规的 Form
,添加了一个 MonthCalendar
和两个 Label
控件,根据我的喜好设置了各种属性,然后将 InitializeComponent
代码复制到类的 New
方法中。 这是清理后得到的结果
Protected Class Calendar
Inherits System.Windows.Forms.Form
Private MyPicker As NullableDateTimePicker
Private WithEvents Label1 As Label
Private WithEvents Label2 As Label
Private WithEvents MonthCalendar1 As MonthCalendar
Public Sub New(ByRef Picker As NullableDateTimePicker)
MyPicker = Picker
Me.MonthCalendar1 = New MonthCalendar
Me.Label1 = New Label
Me.Label2 = New Label
Me.SuspendLayout()
'
'MonthCalendar1
'
Me.MonthCalendar1.Location = New Point(0, 0)
Me.MonthCalendar1.Margin = New Padding(0)
Me.MonthCalendar1.MaxSelectionCount = 1
Me.MonthCalendar1.Name = "MonthCalendar1"
Me.MonthCalendar1.ShowTodayCircle = False
Me.MonthCalendar1.TabIndex = 0
'
'Label1
'
Me.Label1.Font = New Font("Microsoft Sans Serif", 8.25!, _
FontStyle.Underline, GraphicsUnit.Point, CType(0, Byte))
Me.Label1.ForeColor = SystemColors.HotTrack
Me.Label1.Location = New Point(2, 163)
Me.Label1.Name = "Label1"
Me.Label1.Size = New Size(55, 13)
Me.Label1.TabIndex = 1
Me.Label1.Text = "Clear date"
'
'Label2
'
Me.label2.AutoSize = True
Me.label2.Font = New Font("Microsoft Sans Serif", 8.25!, _
FontStyle.Underline, GraphicsUnit.Point, CType(0, Byte))
Me.label2.ForeColor = System.Drawing.SystemColors.HotTrack
Me.label2.Location = New System.Drawing.Point(192, 163)
Me.label2.Name = "Label2"
Me.label2.Size = New System.Drawing.Size(33, 13)
Me.label2.TabIndex = 2
Me.label2.Text = "Close"
'
'CalendarPopup
'
Me.AutoScaleDimensions = New SizeF(6.0!, 13.0!)
Me.AutoScaleMode = AutoScaleMode.Font
Me.ClientSize = New Size(228, 184)
Me.ControlBox = False
Me.Controls.Add(Me.Label1)
Me.Controls.Add(Me.Label2)
Me.Controls.Add(Me.MonthCalendar1)
Me.FormBorderStyle = FormBorderStyle.FixedToolWindow
Me.MaximizeBox = False
Me.MinimizeBox = False
Me.Name = "CalendarPopup"
Me.ShowIcon = False
Me.ShowInTaskbar = False
Me.StartPosition = FormStartPosition.Manual
Me.ResumeLayout(False)
End Sub
Public Property SelectedDate() As Date?
Get
If Information.IsDate(MonthCalendar1.SelectionStart) Then
Return MonthCalendar1.SelectionStart
Else
Return Nothing
End If
End Get
Set(ByVal value As Date?)
If Information.IsDate(value) Then
MonthCalendar1.SetDate(Convert.ToDateTime(value))
Else
MonthCalendar1.SetDate(DateTime.Now)
End If
End Set
End Property
Private Sub Label1_Click(ByVal sender As Object, ByVal e As EventArgs) _
Handles Label1.Click
'Clear
MyPicker.Value = Nothing
Me.Close()
End Sub
Private Sub Label2_Click(ByVal sender As Object, ByVal e As EventArgs) _
Handles Label2.Click
'Close
Me.Close()
End Sub
Private Sub MonthCalendar1_DateSelected(ByVal sender As Object, _
ByVal e As DateRangeEventArgs) _
Handles MonthCalendar1.DateSelected
MyPicker.Value = e.Start
Me.Close()
End Sub
End Class
NullableDateTimePicker
有一个私有变量 Cal
,它用作控件的弹出窗口形式的实例。 当单击控件的按钮时,如果需要,将实例化 Cal
,设置为屏蔽编辑框中的值(如果它是一个有效的日期)或当前日期(如果不是),并显示为模态表单。
Private Sub Button1_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) _
Handles Button1.MouseDown
If Cal Is Nothing Then Cal = New Calendar(Me)
If Cal.Visible Then Exit Sub
If Information.IsDate(MaskedTextBox1.Text) Then
Cal.SelectedDate = Convert.ToDateTime(MaskedTextBox1.Text)
Else
Cal.SelectedDate = Nothing
End If
Cal.Location = Button1.PointToScreen(New Point(0, 19))
Cal.ShowDialog()
End Sub
从控件中获取日期非常简单。 我实现了 HasDate
,它指示控件是否显示有效日期,Text
,它返回屏蔽编辑框的 Text
属性,以及 Value
,它返回一个 Nullable(Of Date)
值(在 VB 2008 中缩写为 Date?
)。
Public ReadOnly Property HasDate() As Boolean
Get
Return Information.IsDate(MaskedTextBox1)
End Get
End Property
Public Overrides Property Text() As String
Get
Return MaskedTextBox1.Text
End Get
Set(ByVal value As String)
MaskedTextBox1.Text = value
End Set
End Property
Public Property Value() As Date?
Get
If Me.HasDate Then
Return Convert.ToDateTime(MaskedTextBox1.Text)
Else
Return Nothing
End If
End Get
Set(ByVal value As Date?)
If Information.IsDate(value) Then
MaskedTextBox1.Text = _
Convert.ToDateTime(value).ToString("MM/dd/yyyy")
Else
MaskedTextBox1.Text = ""
End If
End Set
End Property
改进空间
这个控件非常基本,但它满足了我的需求:允许用户轻松选择日期,手动输入日期,并表示没有日期。 使其数据绑定应该很容易。 更改日历弹出窗口外观的属性也会很方便。
关注点
请注意上面使用了 Information.IsDate
。 Information
是在 Microsoft.VisualBasic
命名空间中找到的静态类。 我这样编写代码是为了帮助可能想要翻译此控件的 C# 程序员; 我认为 C# 没有任何真正等同于 IsDate
的东西。 要使用此函数(以及一些其他有用的工具),请在您的项目中添加对该命名空间的引用。
如上所述,Visual Basic 2008 为 Nullable(Of T)
添加了简写符号,其中 T
是一个值类型。 这是通过在声明中的变量名或变量类型之后添加一个 ?
来指示的。 因此,我对 Date?
的使用实际上与使用 Nullable(Of Date)
相同; 事实上,我相信,无论哪种方式编译都是一样的。
历史
- 2008-05-15 - 向弹出控件添加了第二个标签,允许用户在不更改显示值的情况下关闭表单,并更改了文章的文本以反映这一点。 我还稍微扩展了 VB 中新的
Nullable
简写符号。