我最终编写了一个自定义控件来以正确的方式处理这个问题。我创建了一个带有按钮的文本框,并添加了一个 MonthCalendar 控件。
文本框+按钮打开 MonthCalendar 控件。现在选择日期时间的唯一方法是通过 MonthCalendar。您不能从文本框中进行选择。我还创建了一个在选择日期时触发的自定义事件。它完美地工作。下面的代码:
Public Class CustomDatePicker
'Variables
Friend WithEvents cal As MonthCalendar
Private _isCalendarVisible As Boolean = False
Private _currentSelectedDate As DateTime = Nothing
'Events
Public Event OnDateTimeSet(ByVal sender As Object, ByVal dateValue As DateTime)
Public Event OnDateCleared(ByVal sender As Object)
'Constructor
Public Sub New()
InitializeComponent()
End Sub
'Onload
Private Sub CustomDatePicker_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Initially setup calendar
cal = New MonthCalendar
cal.Name = "Calendar"
cal.MaxSelectionCount = 1
cal.BringToFront()
cal.Location = New Point(Me.Location.X + 5, Me.Location.Y + 25)
Me.Parent.Controls.Add(cal)
cal.Hide()
_isCalendarVisible = False
End Sub
'Returns the currently selected date from the TextBox field
Public ReadOnly Property CurrentSelectedDate()
Get
Return _currentSelectedDate
End Get
End Property
'Display calendar
Private Sub ShowCalendar()
'Close any other custom date controls that are open on the parent form
Dim cont As Control
For Each cont In Parent.Controls
If (cont.GetType().Name = "CustomDatePicker") Then
CType(cont, CustomDatePicker).HideCalendar()
End If
Next
'display the calendar
If Not (_isCalendarVisible) Then
tbxSelectedDate.BackColor = Color.Cornsilk
cal.BringToFront()
cal.Show()
cal.Focus()
_isCalendarVisible = True
btnCalendarToggle.Checked = True
End If
End Sub
'Hide the Calendar
Private Sub HideCalendar()
If (_isCalendarVisible) Then
tbxSelectedDate.BackColor = Color.White
cal.Hide()
_isCalendarVisible = False
btnCalendarToggle.Checked = False
tbxSelectedDate.Focus()
End If
End Sub
'Display the selected datetime into the textbox
Private Sub SetDateTime()
Me.tbxSelectedDate.Text = FormatDateTime(cal.SelectionRange.Start, DateFormat.LongDate)
_currentSelectedDate = FormatDateTime(cal.SelectionRange.Start, DateFormat.LongDate)
RaiseEvent OnDateTimeSet(Me, _currentSelectedDate)
End Sub
'Event when selection is made in the Calendar
Private Sub Calendar_Selection(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DateRangeEventArgs) Handles cal.DateSelected
SetDateTime()
HideCalendar()
End Sub
'Handle the keyboard events associated with the calendar control
Private Sub Calendar_KeyPress(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles cal.KeyPress
If e.KeyChar = ChrW(Keys.Return) Then
SetDateTime()
HideCalendar()
ElseIf e.KeyChar = ChrW(Keys.Escape) Then
HideCalendar()
End If
End Sub
'Handles keypresses on the textbox field
Private Sub tbxSelectedDate_KeyUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles tbxSelectedDate.KeyUp
If (e.KeyCode = Keys.Down) Then
ShowCalendar()
ElseIf (e.KeyCode = Keys.Delete) Then
tbxSelectedDate.Text = ""
End If
End Sub
'Show the calendar when button is clicked
Private Sub btnCalendarToggle_MouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles btnCalendarToggle.MouseUp
ToggleCalendar()
End Sub
'Show the calendar when button is 'clicked' via ENTER on keyboard
Private Sub btnCalendarToggle_KeyPress(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles btnCalendarToggle.KeyPress
If e.KeyChar = ChrW(Keys.Return) Then
ToggleCalendar()
End If
End Sub
'Toggle calender. If on, turn off. If off, turn on.
Private Sub ToggleCalendar()
If Not (_isCalendarVisible) Then
ShowCalendar()
btnCalendarToggle.Checked = True
Else
HideCalendar()
btnCalendarToggle.Checked = False
End If
End Sub
'When textbox value is changed, check to see if it was cleared. If cleared, raiseevent.
Private Sub tbxSelectedDate_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tbxSelectedDate.TextChanged
If (tbxSelectedDate.Text = "") Then
_currentSelectedDate = Nothing
RaiseEvent OnDateCleared(Me)
End If
End Sub