I'm creating a visual basic form which contains two date picker controls. I don't like the user having to scroll through calendars to find the correct date. On various sites where I've had to enter a date (usually a birth date), there will be 3 "dials", one each for month, day and year, and you scroll around each one and then select the date you want. Does anyone know if this can be set up in vb? I've searched the internet and also through documentation for date pickers but I couldn't find anything. I'd appreciate knowing if: a) this can be done in visual basic, and b) if so, where I could find instructions on how to do it.
CodePudding user response:
Not an exact solution but it works pretty closely. Instead of using a DatePicker control, I'm using three combo boxes - one each for month, day and year. These combo boxes are loaded when the form loads. Once the user has selected a proper value for each (some checking has to be done to eliminate such things as February 30th), I concatenate the values from the three boxes and convert to date format. This seems to work pretty well.
CodePudding user response:
Actual solution along the lines of your own answer:
Controls in designer:
DateTimePicker1 As DateTimePicker
YearComboBox As ComboBox
MonthComboBox As ComboBox
DayComboBox As ComboBox
Private earliestYear As Integer = 1900
Private latestYear As Integer = DateTime.Now.Year ' x ' if going x years into the future
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
setDataSources(DateTime.Today)
End Sub
Private Sub setDataSources(d As DateTime)
RemoveHandler YearComboBox.SelectedValueChanged, AddressOf YearMonthComboBox_SelectedValueChanged
RemoveHandler MonthComboBox.SelectedValueChanged, AddressOf YearMonthComboBox_SelectedValueChanged
RemoveHandler DayComboBox.SelectedValueChanged, AddressOf DayComboBox_SelectedValueChanged
Dim yearDataSource = Enumerable.
Range(earliestYear, DateTime.Now.Year - earliestYear 1).
OrderByDescending(Function(y) y).
ToList()
YearComboBox.DataSource = yearDataSource
YearComboBox.SelectedItem = d.Year
Dim monthDataSource = DateTimeFormatInfo.CurrentInfo.MonthNames.
Where(Function(month) Not String.IsNullOrEmpty(month)).
Select(Function(month, i) New KeyValuePair(Of Integer, String)(i 1, month)).
ToList()
MonthComboBox.DisplayMember = "Value"
MonthComboBox.ValueMember = "Key"
MonthComboBox.DataSource = monthDataSource
MonthComboBox.SelectedValue = d.Month
Dim dayDataSource = Enumerable.
Range(1, DateTime.DaysInMonth(d.Year, d.Month)).
ToList()
DayComboBox.DataSource = dayDataSource
DayComboBox.SelectedItem = d.Day
AddHandler YearComboBox.SelectedValueChanged, AddressOf YearMonthComboBox_SelectedValueChanged
AddHandler MonthComboBox.SelectedValueChanged, AddressOf YearMonthComboBox_SelectedValueChanged
AddHandler DayComboBox.SelectedValueChanged, AddressOf DayComboBox_SelectedValueChanged
End Sub
Private Sub YearMonthComboBox_SelectedValueChanged(sender As Object, e As EventArgs)
Dim daysInMonth = DateTime.DaysInMonth(CInt(YearComboBox.SelectedItem), CInt(MonthComboBox.SelectedValue))
Dim selectedDay = CInt(DayComboBox.SelectedItem)
Dim dayDataSource = Enumerable.Range(1, daysInMonth).ToList()
DayComboBox.DataSource = dayDataSource
DayComboBox.SelectedItem = Math.Min(daysInMonth, selectedDay)
DateTimePicker1.Value = New DateTime(CInt(YearComboBox.SelectedItem), CInt(MonthComboBox.SelectedValue), CInt(DayComboBox.SelectedItem))
End Sub
Private Sub DayComboBox_SelectedValueChanged(sender As Object, e As EventArgs)
DateTimePicker1.Value = New DateTime(CInt(YearComboBox.SelectedItem), CInt(MonthComboBox.SelectedValue), CInt(DayComboBox.SelectedItem))
End Sub
Private Sub DateTimePicker1_ValueChanged(sender As Object, e As EventArgs) Handles DateTimePicker1.ValueChanged
setDataSources(DateTimePicker1.Value)
End Sub
Interaction with each control will update other controls accordingly, taking into account number of days per month and leap years.