Passing arguments to methods in VB - vb.net

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

Related

VB.NET: Add\remove row indexes of datagridview checkboxes rows

I am working with forms in VB.NET
There is a DatagridView table with a checkbox column.
See the picture below:
I am interested in the question: how to add the line index to the list when clicking in the checkbox (when we activate the checked status), and remove it from the list when we uncheck the checkbox?
Tried the following but this is not the correct solution:
If e.ColumnIndex = chk_column.Index Then
If e.RowIndex >= 0 Then
Try
For Each row As DataGridViewRow In dataGridNames.Rows
Dim cell As DataGridViewCheckBoxCell = TryCast(row.Cells(5), DataGridViewCheckBoxCell)
If cell.Value Is cell.FalseValue Then
bList_indexes.Add(DataGridnames.CurrentCell.RowIndex)
Exit For
Else 'If cell.Value Is cell.TrueValue Then
bList_indexes.RemoveAt(DataGridnames.CurrentCell.RowIndex)
End If
Next
Catch ex As Exception
'Show the exception's message.
'MessageBox.Show(ex.Message)
'Throw New Exception("Something happened.")
End try
End If
End If
Using DataSources allows you to take the logic out of mucking around in DataGridView events. You shouldn't perform [much] business logic on the UI anyways.
Here is the class I used to represent your data.
Public Class ClassWithSelect
Public Property [Select] As Boolean
Public Property Name As String
Public Sub New(s As Boolean, n As String)
Me.Select = s
Me.Name = n
End Sub
End Class
And all the code to set DataSources
Private myDataSource As List(Of ClassWithSelect)
Private selectedIndices As List(Of Integer)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
myDataSource = Enumerable.Range(65, 10).Select(Function(i) New ClassWithSelect(False, Chr(i).ToString())).ToList()
DataGridView1.DataSource = myDataSource
updateSelectedIndices()
End Sub
Private Sub DataGridView1_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellValueChanged
updateSelectedIndices()
End Sub
Private Sub DataGridView1_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick
DataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit)
End Sub
Private Sub updateSelectedIndices()
selectedIndices = New List(Of Integer)()
For i = 0 To myDataSource.Count - 1
If myDataSource(i).Select Then selectedIndices.Add(i)
Next
ListBox1.DataSource = selectedIndices
End Sub
And the end result
Now you don't need to access the UI to get the indices for further processing as they are in the class-level variable selectedIndices. The UI is meant for user I/O, NOT for storing state.
Note: The event handler was taken from this answer but this answer is also linked as an improvement to the check change handler, but I felt the complexity would distract from my answer. If you find you need to click fast, look into the latter.
Also Note: The method updateSelectedIndices() should have inside it an InvokeRequired check if you plan to perform work off the UI thread

Visual basic empty text box throws exception

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

Alternative Process

I have 2 buttons and a DataGridView with 2 Columns (0 & 1).
The 1st button transfers a randomized cell from the Column(1) to a TextBox. Then, it stores that Cell in variable (a), plus the cell that opposites it in variable (b).
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim rnd As New Random
Dim x As Integer = rnd.Next(0, Form1.DataGridView1.Rows.Count)
Dim y As Integer = 1
Dim a As String = Form1.DataGridView1.Rows(x).Cells(y).Value
Dim b As String = Form1.DataGridView1.Rows(x).Cells(y - 1).Value
TextBox3.Text = a
End Sub
The 2nd button, however, is supposed to compare if another TextBox's text has the same string variable (b) has as Strings. Now, if so, then it has to display a certain message and so on...
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
If TextBox4.Text = b Then '<<< ISSUE HERE!
MsgBox("Correct! ^_^")
ElseIf TextBox4.Text = "" Then
MsgBox("You have to enter something first! O_o")
Else
MsgBox("Wrong! >,<")
End If
End Sub
The problem is that the variable (b) is surely not shared across the two "private" subs. And so, there is NOTHING to compare to in the 2nd button's sub! I presume that the solution here is to split the "randomization process" into a separate function, then execute it directly when the 1st button gets activated. Furthermore, that function's variables have to be SHARED somehow, and I certainly don't know how!
Thanks for Mr. Olivier, the code has been improved significantly! Yet, I still encounter a "wrong" comparison issue, somehow!
Dim RND As New Random
Dim x As Integer
Private Function GetCell(ByVal rowIndex As Integer, ByVal cellIndex As Integer) As String
Return Form1.DataGridView1.Rows(rowIndex).Cells(cellIndex).Value
End Function
Private Sub btnRoll_Click(sender As Object, e As EventArgs) Handles btnRoll.Click
x = RND.Next(0, Form1.DataGridView1.Rows.Count)
tbxRoll.Text = GetCell(x, 1)
End Sub
Private Sub btnSubmit_Click(sender As Object, e As EventArgs) Handles btnSubmit.Click
If tbxSubmit.Text = GetCell(x, 0) Then
MsgBox("Correct! ^_^")
ElseIf tbxSubmit.Text = "" Then
MsgBox("You have to enter something first! O_o")
Else
MsgBox("Wrong! >,<")
End If
End Sub</code>
Well, unbelievably, I read a guide about "comparison operations" in VB.net and tried out the first yet the most primal method to compare equality - which was to use .Equals() command - and worked like a charm! Thank God, everything works just fine now. ^_^
If tbxSubmit.Text.Equals(GetCell(x, 0)) Then
Alright now... This is going to sound weird! But, following Mr. Olivier's advise to investigate "debug" the code, I rapped the string I'm trying to compare with brackets and realized that it's been outputted after a break-line space! So, I used the following function to remove the "white-space" from both of the comparison strings! And it bloody worked! This time for sure, though. ^_^
Function RemoveWhitespace(fullString As String) As String
Return New String(fullString.Where(Function(x) Not Char.IsWhiteSpace(x)).ToArray())
End Function
If RemoveWhitespace(tbxSubmit.Text) = RemoveWhitespace(GetCell(x, 0)) Then
Turn the local variables into class fields.
Dim rnd As New Random
Dim x As Integer
Dim y As Integer
Dim a As String
Dim b As String
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
x = rnd.Next(0, Form1.DataGridView1.Rows.Count)
y = 1
a = Form1.DataGridView1.Rows(x).Cells(y).Value
b = Form1.DataGridView1.Rows(x).Cells(y - 1).Value
TextBox3.Text = a
End Sub
These fields can now be accessed from every Sub, Function and Property.
Of course Button3_Click must be called before Button2_Click because the fields are initialized in the first method. If this is not the case then you should consider another approach.
Create a function for the Cell access
Private Function GetCell(ByVal rowIndex As Integer, ByVal cellIndex As Integer) _
As String
Return Form1.DataGridView1.Rows(rowIndex).Cells(cellIndex).Value
End Function
And then compare
If TextBox4.Text = GetCell(x, y - 1) Then
...
And don't store the values in a and b anymore. If y is always 1 then use the numbers directly.
If TextBox4.Text = GetCell(x, 0) Then
...
One more thing: give speaking names to your buttons in the properties grid before creating the Click event handlers (like e.g. btnRandomize). Then you will get speaking names for those routines as well (e.g. btnRandomize_Click).
See:
- VB.NET Class Examples
- Visual Basic .NET/Classes: Fields

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

Search ListBox elements in VB.Net

I'm migrating an application from VB6 to VB.Net and I found a change in the behavior of the ListBox and I'm not sure of how to make it equal to VB6.
The problem is this:
In the VB6 app, when the ListBox is focused and I type into it, the list selects the element that matches what I type. e.g. If the list contains a list of countries and I type "ita", "Italy" will be selected in the listbox.
The problem is that with the .Net version of the control if I type "ita" it will select the first element that starts with i, then the first element that starts with "t" and finally the first element that starts with "a".
So, any idea on how to get the original behavior? (I'm thinking in some property that I'm not seeing by some reason or something like that)
I really don't want to write an event handler for this (which btw, wouldn't be trivial).
Thanks a lot!
I shared willw's frustration. This is what I came up with. Add a class called ListBoxTypeAhead to your project and include this code. Then use this class as a control on your form. It traps keyboard input and moves the selected item they way the old VB6 listbox did. You can take out the timer if you wish. It mimics the behavior of keyboard input in Windows explorer.
Public Class ListBoxTypeAhead
Inherits ListBox
Dim Buffer As String
Dim WithEvents Timer1 As New Timer
Private Sub ListBoxTypeAhead_KeyDown(sender As Object, _
e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
Select Case e.KeyCode
Case Keys.A To Keys.Z, Keys.NumPad0 To Keys.NumPad9
e.SuppressKeyPress = True
Buffer &= Chr(e.KeyValue)
Me.SelectedIndex = Me.FindString(Buffer)
Timer1.Start()
Case Else
Timer1.Stop()
Buffer = ""
End Select
End Sub
Private Sub ListBoxTypeAhead_LostFocus(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.LostFocus
Timer1.Stop()
Buffer = ""
End Sub
Public Sub New()
Timer1.Interval = 2000
End Sub
Private Sub Timer1_Tick(sender As Object, e As System.EventArgs) Handles Timer1.Tick
Timer1.Stop()
Buffer = ""
End Sub
End Class
As you probably know, this feature is called 'type ahead,' and it's not built into the Winform ListBox (so you're not missing a property).
You can get the type-ahead functionality on the ListView control if you set its View property to List.
Public Function CheckIfExistInCombo(ByVal objCombo As Object, ByVal TextToFind As String) As Boolean
Dim NumOfItems As Object 'The Number Of Items In ComboBox
Dim IndexNum As Integer 'Index
NumOfItems = objCombo.ListCount
For IndexNum = 0 To NumOfItems - 1
If objCombo.List(IndexNum) = TextToFind Then
CheckIfExistInCombo = True
Exit Function
End If
Next IndexNum
CheckIfExistInCombo = False
End Function