A reader asked for help coding a loop to use the InputBox to add data to a ListBox control. There were some specific requirements that had to be met as well:
- Only five values could be added to the ListBox
- The input data had to be validated for numeric values between 1 and 100
- Blank input had to be disallowed
After pointing out a few logic errors in the program, it became clear that the real problem was the choice of technology to solve the problem.
- The "holdover" InputBox from VB6 days.
- Using a loop to input data.
There are just better ways to do it now. But if, for some reason, you have to use the InputBox, here's a followup article that explains how to solve one main problem.
I haven't actually tried to write a loop like this since VB.NET came onto the scene, so I gave it a shot just for fun. The first block of code below is what I came up with first.
Click Here to display the illustration
Private Sub AcceptGrades_Click( ByVal sender As System.Object, ByVal e As System.EventArgs ) Handles AcceptGrades.Click Dim dec_grade As Decimal Dim str_inputGrade As String = "" Dim int_counter As Integer = 1 AcceptGrades.Enabled = False Do str_inputGrade = InputBox("Enter grade number " & int_counter.ToString, "Grade Calculator", "Enter Grade") If str_inputGrade = String.Empty Then MessageBox.Show("Nothing entered" & vbNewLine & "Please enter a grade", "Error", MessageBoxButtons.OK, MessageBoxIcon.Information) ElseIf Not IsNumeric(str_inputGrade) Then MessageBox.Show( "Input is not a numeric grade" & vbNewLine & "Please enter a numeric grade", "Error", MessageBoxButtons.OK, MessageBoxIcon.Information) Else dec_grade = CDec(str_inputGrade) If dec_grade >= 0 And dec_grade <= 100 Then GradeOutput.Items.Add(dec_grade) int_counter += 1 Else MessageBox.Show( "Enter a grade between 0-100", "Error", MessageBoxButtons.OK, MessageBoxIcon.Information) End If End If Loop Until int_counter > 5 End Sub
It works, but the code is "brittle". That's a term used for code that breaks easily whan anything is changed. And there are worse problems. For example, once you get into the loop, the only way to get out again is to cancel the program - not a very satisfactory user experience. Adding Cancel capability to the error boxes adds a lot of code and even more complexity. And the InputBox itself has a fatal flaw. The Cancel button in the InputBox returns a "zero length string". But a zero length string is also returned if the user simply forgets to enter anything. There's a way to tell the difference, but it requires using unmanaged code. This article explains how to do it.
Without getting into WPF or ASP.NET where there are even more sophisticated ideas, the best way to improve this program is to simply get rid of the InputBox and loop. Use a simple TextBox to enter the data and use a Label to display messages. And for data validation, code a Validating event for the TextBox control. This puts validation into one self-contained block and data entry into a different one. The global ValidGradeEntry variable guarantees that all the validating checks have been passed. New features (like a "Start Over" button or a button to delete ListBox entries, for example) could be added easily without disturbing any of the existing logic. And you can end the program without completing the loop!
Click Here to display the illustration
Dim ValidGradeEntry As Boolean Private Sub inputGrade_Validating( ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs ) ValidGradeEntry = False ErrorMsg.Text = "" If inputGrade.Text = "" Then ErrorMsg.Text = "Nothing entered" & vbNewLine & "Please enter a grade" ElseIf Not IsNumeric(inputGrade.Text) Then ErrorMsg.Text = "Input is not a numeric grade" & vbNewLine & "Please enter a numeric grade" ElseIf CDec(inputGrade.Text) < 0 Or CDec(inputGrade.Text) > 100 Then ErrorMsg.Text = "Enter a grade between 0-100" Else ValidGradeEntry = True End If End Sub Private Sub btnAcceptGrades_Click( ByVal sender As System.Object, ByVal e As System.EventArgs ) Handles AcceptGrades.Click If ValidGradeEntry = True Then GradeOutput.Items.Add(CDec(inputGrade.Text)) inputGrade.Text = "" If GradeOutput.Items.Count = 5 Then AcceptGrades.Enabled = False ErrorMsg.Text = "5 grades entered" & vbNewLine & "No more input allowed" End If End If inputGrade.Focus() End Sub
It's a minor point, but you might also keep in mind that the VB.NET AndAlso and OrElse operators are "short circuit" operators. That means that if you have a whole list of validating conditions, you can code them as a whole series connected with these operators (with the most frequent hits first) and nothing below a validation test that fails will use any processing.
If <validation test one succeeds> AndAlso <validation test two succeeds> AndAlso ... Then Return <validation successful>
No doubt, there are still better ways. If you can improve on this, send it in!