Visual basic empty text box throws exception - vb.net

The code below is a program to calculate the BMI using text boxes. I am having an issue however that when I clear one of the text boxes it will throw an exception and freeze the program. I was wondering if anyone had an answer on how to prevent this. I already tried setting my variables to 0 and 1 to see if that was the issue but it does not appear to be.
Private Sub tboxWeight_TextChanged(sender As Object, e As EventArgs) Handles tboxWeight.TextChanged
Weight = 0
Weight = Convert.ToInt64(tboxWeight.Text)
End Sub
Private Sub tboxHFeet_TextChanged(sender As Object, e As EventArgs) Handles tboxHFeet.TextChanged
Height_feet = 0
Height_feet = Convert.ToInt64(tboxHFeet.Text)
Get_BMI(1)
End Sub
Private Sub tboxHInch_TextChanged(sender As Object, e As EventArgs) Handles tboxHInch.TextChanged
Height_Inches = 0
Height_Inches = Convert.ToInt64(tboxHInch.Text)
Get_BMI(1)
End Sub
Private Sub tboxAge_TextChanged(sender As Object, e As EventArgs) Handles tboxAge.TextChanged
Age = Convert.ToDouble(tboxAge.Text)
End Sub
Function Get_BMI(ByVal j As Integer) As Double
BMI = (Weight / (Height_Inches + (Height_feet * 12) ^ 2) * 703)
tboxBMI.Text = Convert.ToString(BMI)
Exit Function
End function

It is because you set a textbox into an integer field, so when the textbox is empty it will throw exception because the textbox doesn't contain a number.
Try using If else statement for each textboxes.
String.IsNullOrEmpty function will be sufficient.

Good/Best practice says, you need to validate the data before performing calculation i.e. Get_BMI(). Below code snippet will help you.
Dim textBoxValue As String
If Not String.IsNullOrEmpty(textBoxValue) Then
If IsNumeric(textBoxValue) Then
End If
End If

Related

Changing typing behavior of ListBox

When typing into a listbox the listbox scrolls to the next item with first letter matching the input character. I want to disable/change this behavior.
I implemented a handler for the keypress event and implemented my new behavior, but I don't see any way to remove the old behavior.
How can I disable the default behavior?
Here is the event handler for the keypress event:
Private Sub FooListBox_KeyPress(sender As Object, e As KeyPressEventArgs) Handles FooListBox.KeyPress
If SearchResetTimer.Enabled Then
SearchResetTimer.Stop()
SearchTimer.Stop()
Else
BeginUpdate()
SearchedString = ""
End If
SearchedString = SearchedString & e.KeyChar
SearchResetTimer.Start()
SearchTimer.Start()
End Sub
Private Function SearchFor(listbox As ListBox, target As String) As Integer
For i As Integer = listbox.SelectedIndex To listbox.Items.Count - 1
If listbox.Items(i).ToString().ToLower().StartsWith(target) Then
Return i
End If
Next
For i As Integer = 0 To listbox.SelectedIndex - 1
If listbox.Items(i).ToString().ToLower().StartsWith(target) Then
Return i
End If
Next
Return -1
End Function
Private Sub SearchTimer_Tick(sender As Object, e As EventArgs) Handles SearchTimer.Tick
SearchTimer.Stop()
Dim Found As Integer = SearchFor(FooListBox, SearchedString)
If Found <> -1 Then
FooListBox.SelectedIndex = Found
End If
EndUpdate()
End Sub
Private Sub SearchResetTimer_Tick(sender As Object, e As EventArgs) Handles SearchResetTimer.Tick
SearchResetTimer.Stop()
End Sub
Quick overview: there are two timers, searchTimer that when ticked searches for the string and updates the control, searchResetTimer which resets the searched string and marks the beginning of a new user input.
Note that I am not releasing this code under CC, it is for illustration purposes only

Case Statement not working with String Literals

Hi all I am trying to learn VB and am having trouble with some code I am using. I would like my program to output a specific number based on if a check box is checked using case statements but my code is not working.
Public Class frmBTPW
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles btncalc.Click
Dim dblhdr As Double
Dim dblfdr As Double
Dim dbltdr As Double
dblhdr = 24
dblfdr = 35
dbltdr = 50
Select Case "Power Wash Rental"
Case "Half Day Rental"
If chkhd.Checked = True Then
txtrc.Text = "poop"
End If
Case "Full Day Rental"
If chkFD.Checked = True Then
txtrc.Text = dblfdr
End If
End Select
End Sub
Private Function Button1_Click() As CheckBox
Throw New NotImplementedException
End Function
End Class
Help would be greatly appreciated.My code isn't outputting anything in the text-box.
Beyond case statements, respectfully I think you should read up on the distinction between a literal value and a variable. "Power Wash Rental" is nothing more than a series of characters, AKA a string: (In this case "P" followed by "o" etc.) Likewise, "Half Day Rental" is a series of characters, "H" followed by "a" etc.)
"Power Wash Rental" is a literal string. So is ""Half Day Rental" and of course they will never match.
Whereas:
Dim A as string
A = TextBox1.text
Now, A is a variable. It is a string which contains whatever series of characters (text) is typed into the textbox.
This is a simple way to do it.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
chkhd.tag = 24 ' store values in the check boxes
chkfd.tag = 35 ' using the tag property
chktd.tag = 50 ' and later add up the values
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles btncalc.Click
dim total as double = 0
total += IF(chkhd.checked, cdbl(chkhd.tag), 0)
total += IF(chkfd.checked, cdbl(chkfd.tag), 0)
total += IF(chktd.checked, cdbl(chktd.tag), 0)
msgbox(total)
End Sub
However, I think you might want radio buttons instead of checkboxes.
Checkboxes can all be checked. Radio buttons can only have one at a time.
This solution allows you to keep your price with the checkbox -- you could do this in the form designer instead of form load.
I would recommend reading up on Case Statements. Currently you will never get anywhere as your using a string to what, nothing. You also do not need a case for this... Also if the first condition is true and the last one is as well, the last one win's for setting the text, didn't know if you had this there for a reason or not?
If chkhd.Checked = True Then
txtrc.Text = "poop"
End If
If chkFD.Checked = True Then
txtrc.Text = dblfdr
End If
As others have stated your Case statement isn't working because you are using string literals to compare "Power Wash Rental" to "Half Day Rental" which will always be false. Plutonix was also correct in saying that a ComboBox for the rental duration should be used. The only reason not to be is if you were calculating cumulative rental days/amounts; however in that situation you should be using some sort of NumericUpDown for your multiplier against a time duration.
Here is an example that should help you get started. You could make the structure into a type of keyed collection or make it a wrapper class for a dictionary object which would make be easier to use in code. The following may not be exactly plug-and-play with your project, however it should help give you some ideas on how to handle the situation.
Option Strict On
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.ComboBox1.Items.AddRange({PowerWashRentals.halfDayText, PowerWashRentals.FullDayText, PowerWashRentals.TwoDayText})
AddHandler ComboBox1.SelectedValueChanged, AddressOf Me.ComboBox1_SelectedChanged
End Sub
Private Sub ComboBox1_SelectedChanged(sender As Object, e As EventArgs)
Dim cBox As ComboBox = DirectCast(sender, ComboBox)
Select Case cBox.SelectedItem.ToString
Case PowerWashRentals.halfDayText
Label1.Text = PowerWashRentals.HalfDayPrice.ToString
Case PowerWashRentals.FullDayText
Label1.Text = PowerWashRentals.FullDayPrice.ToString
Case PowerWashRentals.TwoDayText
Label1.Text = PowerWashRentals.TwoDayPrice.ToString
End Select
End Sub
End Class
Public Structure PowerWashRentals
Public Const HalfDayPrice As Double = 24
Public Const FullDayPrice As Double = 35
Public Const TwoDayPrice As Double = 50
Public Const halfDayText As String = "Half Day Rental"
Public Const FullDayText As String = "Full Day Rental"
Public Const TwoDayText As String = "Two Day Rental"
End Structure

Is this program efficient

I've put together a small calculator application that works quite well, but despite being a novice to VB.net I know that the program probably isn't as efficient as it should be. The idea is that upon inputting numbers into a textbox and pressing a mathematical operator, the textbox will reset and continue the equation, storing the past values entered.
Dim input1 As Double
Dim numfunction As Double
'numerical functions (null = 0, add = 1, subtract = 2, divide = 3, multiply = 4)
Private Sub btnAdd_Click(sender As Object, e As RoutedEventArgs) Handles btnAdd.Click
If txtNum.Text = "" Then
MsgBox("Please enter a number")
Else
numfunction = 1
input1 = input1 + txtNum.Text
txtNum.Text = ""
End If
End Sub
Private Sub btnEqual_Click(sender As Object, e As RoutedEventArgs) Handles btnEqual.Click
If txtNum.Text = "" Then
MsgBox("Please enter a final number")
End If
If numfunction = 1 Then
txtNum.Text = txtNum.Text + input1
input1 = 0
End If
End Sub
Could you point me in the right direction as to what I should replace add or remove to make my programs more efficient in the future? Keep in mind that the BtnAdd_Click event is just one of 4 (add, sub, divide, multiply) and because of that btnEqual_Click will have a few if statements, checking for what function the user has put in, and if there is anything in txtNum at all.
Thanks in advance, I'm not asking for anyone to complete my code, but I'd love to see what options I have so I make more efficient programs in the future.
With a little initial effort you could simplify this task by using the power of object oriented programming:
Public Class Form1
' hold a reference to all operations in a list of operations
Private _operations As New List(Of Operation)
' the operation currently choosen
Private Property _currentOperation As Operation
' the 2 numbers you want to perform the operations on
Private _number1 As Double = 0
Private _number2 As Double = 0
Public Sub New()
InitializeComponent()
SetupOperations()
TextBox1.Text = 0
End Sub
Public Sub ChangeOperation(operation As Operation)
_number1 = _currentOperation.FunctionDelegate.Invoke(_number1, _number2)
TextBox1.Text = _number1
_currentOperation = operation
End Sub
Private Sub SetupOperations()
_operations.Add(New Operation(Me, btnAdd, Function(x, y)
Return x + y
End Function))
' heres the crux ... you use anonymous method to define your functions hook them to the form (Me) and the related Button
' all at once
' Similar for the other operations (subtract / multiply / divide / pow, and so on)
Dim equalsOperation As New Operation(Me, btnEqual, Function(x, y)
Return y
End Function)
_operations.Add(equalsOperation)
_currentOperation = equalsOperation
End Sub
' for this example i used only one textbox and a lable indicating wheter the number entered is a valid double
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
Dim result As Double
If Double.TryParse(TextBox1.Text, result) Then
_number2 = result
lblValid.Text = "Valid" ' tell the user that the number entered is valid or not
Else
lblValid.Text = "Invalid"
End If
End Sub
''' <summary>
''' An Operation that hooks up a button click and can execute the operation
''' </summary>
Public Class Operation
Private _owningForm As Form1
Public Property FunctionDelegate As Func(Of Double, Double, Double) ' use a delegate to a Func that returns double with 2 double parameters
Public Sub New(owningForm As Form1, boundButton As Button, functionDelegate As Func(Of Double, Double, Double))
Me.FunctionDelegate = functionDelegate
Me._owningForm = owningForm
AddHandler boundButton.Click, AddressOf boundButton_Click ' make the operation hook up on the click event
End Sub
Private Sub boundButton_Click()
_owningForm.ChangeOperation(Me)
End Sub
End Class
End Class
Hope this is not too confusing for you, I intended to show you a bigger world than simple routines and tons of eventhandlers
You could simplify your code by inserting your checking code into a separate subroutine.
Sub CheckVals()
If txtNum.Text = "" Then
MsgBox("Please enter a final number")
End If
If numfunction = 1 Then
txtNum.Text = txtNum.Text + input1
input1 = 0
End If
End Sub
You would then reference this sub from your two button click events.
Private Sub btnAdd_Click(sender As Object, e As RoutedEventArgs) Handles btnAdd.Click
CheckVals()
End Sub

Passing arguments to methods in VB

I'm hoping you guys can help with a problem that should be simple to solve, I've just had issues finding a solution. In the program that I'm writing some of the textbox's have to be numeric between 1 and 10, and others just have to be numeric. Instead of coding each textbox to verify these parameters I decided to write methods for each of them. I'm having problems passing the arguments and getting it to function correctly. Included is some of my code that shows what I'm trying to accomplish.
Public Shared Sub checkforonetoten(ByVal onetoten As Double)
If (onetoten > 1 & onetoten < 10) Then
Else
MessageBox.Show("Please enter a Number between 1-10", "Error")
End If
End Sub
Public Shared Sub checkfornumber(numCheck As Double)
Dim numericCheck As Boolean
numericCheck = IsNumeric(numCheck)
If (numericCheck = False) Then
MessageBox.Show("Please enter a number", "Error")
End If
End Sub
Private Sub textboxS_TextChanged(sender As Object, e As EventArgs) Handles textboxS.TextChanged
Dim S As Double
S = textboxS.Text
checkfornumber(S)
checkforonetoten(S)
End Sub
One of your main problems is you're converting your text without validating it. You're also programming without the Options On to warn you of bad conversion techniques like you're using in the event handler.
The TryParse method would come in handy here:
Private Sub textboxS_TextChanged(sender As Object, e As EventArgs) Handles textboxS.TextChanged
Dim S As Double
If Double.TryParse(textboxS.Text, S) Then
checkforonetoten(S)
End If
End Sub
Since the TryParse method validates your text and sets the value to 'S', you only need to check the range.
Of course using NumericUpDown controls would make all this moot, since the values will always only be numbers and you can set the range on each one.
one way to structure it is to have one event procedure process the similar TB types:
Private Sub textboxS_TextChanged(sender As Object, e As EventArgs) _
Handles textbox1.TextChanged, textbox12.TextChanged, _
Handles textbox16.TextChanged
Dim S As Double
If Double.TryParse(Ctype(sender, TextBox).Text, S) Then
' or place the Check code here for all the TextBoxes listed above
checkforonetoten(S)
End If
End Sub
The plain numeric kind:
Private Sub textboxQ_TextChanged(sender As Object, e As EventArgs) _
Handles textbox2.TextChanged, textbox6.TextChanged
Dim S As Double
If Double.TryParse(Ctype(sender, TextBox).Text, S) = False Then
MessageBox.Show("Please enter a number", "Error")
End If
End Sub
Rather than calling a function and passing the current TextBox from events (which is fine), have 2 or 3 events process them all. The point is adding/moving the Handles clause to a common event procedure (be sure to delete the old ones).
If you do decide to call a common function, dont do anything in the events (you still have one per TB) and do it all in the common proc:
Private Sub textboxS_TextChanged(sender As Object, e As EventArgs) _
Handles textboxS.TextChanged
checkforonetoten(Sender)
End Sub
private Sub checkforonetoten(tb As Textbox)
Dim S As Double
If Double.TryParse(tb.Text, S) Then
' your check for 1 - 10 on var S
else
' error: not a valid number
End If
end sub
Also:
If (onetoten > 1 & onetoten < 10) Then
should be:
If (onetoten > 1) AndAlso (onetoten < 10) Then

Checkbox returned in Event Handler isn't one on form

I'm creating an array of checkboxes on a form dynamically; the code that creates the array looks like this:-
checkbox_array(count_of_checkboxes) = New CheckBox
if (count_of_checkboxes = 0) Then
checkbox_array(count_of_checkboxes).Top = specimen_checkbox.Top
checkbox_array(count_of_checkboxes).Left = specimen_checkbox.Left
else
checkbox_array(count_of_checkboxes).Top = checkbox_array(count_of_checkboxes - 1).Top + vertical_offset
checkbox_array(count_of_checkboxes).Left = checkbox_array(count_of_checkboxes - 1).Left + horizontal_offset
End If
my_panel.Controls.Add(checkbox_array(count_of_checkboxes))
AddHandler checkbox_array(count_of_checkboxes).MouseClick, cbxSpecimen_CheckedChanged
checkbox_array(count_of_checkboxes).Name = someValue
checkbox_array(count_of_checkboxes).Text = someValue
checkbox_array(count_of_checkboxes).Enabled = true
checkbox_array(count_of_checkboxes).Visible = true
checkbox_array(count_of_checkboxes).Show()
This works fine and dandy on one form. However, I am using the same code on a form which is derived from a base form, and running into a problem, in that the object returned in the sender parameter, although clearly a checkbox with a recognisable name, isn't any of the checkboxes in the array.
I verified this with:-
Private Sub cbxSpecimen_CheckedChanged( sender As System.Object, e As System.EventArgs) Handles cbxSpecimen.CheckedChanged
For i As Integer = 0 To checkbox_array.GetUpperBound(0) - 1
If checkbox_array(i).Equals(sender) Then
// set a breakpoint here
End If
Next i
End Sub
Can anyone shed any light on why this should work on a normal form, but not a derived-class form?
I verified this with:-
Private Sub cbxSpecimen_CheckedChanged( sender As System.Object, e As System.EventArgs)
Handles cbxSpecimen.CheckedChanged
For i As Integer = 0 To checkbox_array.GetUpperBound(0) - 1
If checkbox_array(i).Equals(sender) Then
// set a breakpoint here
End If
Next i
End Sub
Why checkbox_array.GetUpperBound(0) - 1? This will skip the last element in the array. Try:
For i As Integer = 0 To checkbox_array.GetUpperBound(0)
If checkbox_array(i).Equals(sender) Then
// set a breakpoint here
End If
Next i
Or
For i As Integer = 0 To checkbox_array.Length - 1
...
I have managed to get this to work by refilling the array of checkboxes inside the click event:-
Private Sub cbxSpecimen_CheckedChanged(sender As System.Object, e As System.EventArgs) Handles cbxSpecimen.CheckedChanged
For i As Integer = 0 To check_boxes.GetUpperBound(0)
If check_box_array(i).Name = CType(sender, CheckBox).Name And
Not check_box_array(i).Equals(sender) Then
check_box_array(i) = CType(sender, CheckBox)
End If
Next i
' do useful work
End Sub
After the check box on the form has been stuffed back into the array, it remains there (so the second invokation for the same checkbox doesn't insert into the array a second time).
This seems like a ghastly hack to me, but I'll go with it for the time being.