How do I validate user input? - vb.net

So I'm having a problem with my code. I need to validate if the user input is a number or not in a textbox. Now I can get it to see whether or not it is a number and it displays the error message just fine but the problem is that the word still gets inputted in to the textbox when I want there to be only numbers
If tried using if not IsNumeric(Number) then
msgbox.show("ERROR! Data must be a number!")
'Getting user input
Dim Number As String = Me.InputTextbox.Text
UnitsTextbox.AppendText(Environment.NewLine & Number)
'Make the textbox delete the text once the button is clicked
InputTextbox.Text = String.Empty
If Not IsNumeric(Number) Then
MsgBox("ERROR! Data must be a number")
End If
I'm expecting it to accept numbers only
i have a text box for input and a textbox for the results and when the number comes up false I want it to not show in the results textbox

As per #Jens comments, only I changed it to .TryParse. IsNumeric is an old VB6 method that has been optimized in .Net to TryParse.
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim output As Integer
If Not Integer.TryParse(InputTextbox.Text, output) Then
MessageBox.Show("ERROR! Data must be a number")
Else
UnitsTextbox.AppendText(Environment.NewLine & InputTextbox.Text)
InputTextbox.Text = String.Empty
End If
End Sub

Related

How to pass a value to DGV Cell when its formatted to C2 format

I'm struggling find a specific answer to this question, therefore asking it myself...
I have a DataGridView with columns which has the following formatting applied to it:
DGV.Columns(3).DefaultCellStyle.Format = "C2"
On the form there is a text box in which the user enters a number and that value is then entered in one of the cells in DGV:
For Each dr As DataGridViewRow In DGV.Rows
dr.Cells("ColumnHeader").Value = TextBox.Text
Next
Before the above code is executed, this event occurs on the TextBox to format its value:
Private Sub TextBox_Leave(sender As Object, e As EventArgs) Handles TextBox.Leave
TextBox.Text = FormatCurrency(TextBox.Text)
End Sub
The text within the TextBox is displaying correctly as a currency, but when the code to put that into a cell in the DGV executes it fails saying the value is in incorrect format.
Is DGV.Columns(3).DefaultCellStyle.Format = "C2" different format to FormatCurrency(TextBox.Text)?
That is all wrong. "C2" is a numeric format string, so it will only work on numbers. A String containing digit characters is not a number and a String containing currency text definitely isn't. You need to get the String from the TextBox, concert that to a number (probably Decimal for currency values) and then load that number into the grid. The grid converts that number, along with all the data, into text to display and will use your format string to do so:
dr.Cells("ColumnHeader").Value = CDec(TextBox.Text)
You would, presumably, already have validated the user input by this stage, so there's no possibility of CDec throwing an exception.
If the intent is to display the data formatted as currency in both the grid and the TextBox then you should get rid of your Leave event handler and handle the Validating and Validated events instead. The first will validate the input to ensure that it is numeric and the second will do the formatting:
Private Sub TextBox1_Validating(sender As Object, e As CancelEventArgs) Handles TextBox1.Validating
If Not Decimal.TryParse(TextBox1.Text, NumberStyles.Currency, Nothing, Nothing) Then
'Don't let the control lose focus when it contains invalid data.
e.Cancel = True
End If
End Sub
Private Sub TextBox1_Validated(sender As Object, e As EventArgs) Handles TextBox1.Validated
TextBox1.Text = Decimal.Parse(TextBox1.Text, NumberStyles.Currency).ToString("C2")
End Sub
That code will allow the user to enter the currency symbol or not, but it will ensure that the format is currency with two decimal places once it loses focus. You would then need to allow for the formatting when copying to the grid:
dr.Cells("ColumnHeader").Value = Decimal.Parse(TextBox1.Text, NumberStyles.Currency)

Sum of Numbers with LOOPING

So for my class I am trying to do write a code that sums up numbers from 1-10. For example if a user puts in 3, the that program will add 1+2+3 and the final answer would be 6.......I am trying to do this using looping and also with a display mesage that gives the answer.
this is the code I have so far........
Option Strict On
Public Class frmSumOfNumbers
Private Sub btnEnterNumbers_Click(sender As Object, e As EventArgs) Handles btnEnterNumbers.Click
'For loop from 0 to counter -1
InputBox("Enter A Positive integer value", "Input needed", "10")
End Sub
Function Validation(ByVal PositiveNumber As Double, ByRef Result As Double) As Boolean
If PositiveNumber > -1 Then
Result = CDbl(PositiveNumber)
Else
'pop message box and return false if not positive
MessageBox.Show("Please enter positive numbers only")
Return False
End If
End Function
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
' Closes the program
Close()
End Sub
End Class
Your first problem is providing a place to collect the input values from the user. Take a look at the InputBox Function https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualbasic.interaction.inputbox?view=netframework-4.8
Notice that is returns a string. We can get the input from the user by providing a String variable.
Dim UserInput As String
UserInput = InputBox("Enter A Positive integer value", "Input needed", "10")
But this value will disappear as soon as we reach End Sub! If we use a form level variable to collect the values the variable will be around as long as the form is open. Another advantage of a form level (class level) variable is that it can be seem by any method in the from.
We can use a collection variable like an array or a list. Since we are not sure how many numbers the user will enter let's use a list. With an array we would have to use ReDim Preserve every time we got a new number to resize the array. That isn't necessary with a list. See https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1?view=netcore-3.1
At the Form level...
Private IntegerList as New List(Of Integer)
But the we have a String variable from the user. This is where your validation code comes in. We need to pass the what the user entered in the input box (remember InputBox returns a String) so the datatype of the argument in String. We want to get back an Integer so the datatype of the Function is Integer. Any return statement in the function must be followed by an Integer value.
I used Integer.TryParse to test if the input was a number and then I tested to see if the number is positive. See the docs https://learn.microsoft.com/en-us/dotnet/api/system.int32.tryparse?view=netcore-3.1
If the user input passes the validation then the number is added to the list, otherwise the message is displayed.
To add up the list you can the .Net framework do the loop behind the scenes with the .Sum method of a list or you can use a For Each loop to do it yourself. Same result.
Private IntegerList As New List(Of Integer)
Private Sub AddANumber_Click(sender As Object, e As EventArgs) Handles AddANumber.Click
Dim UserInput = InputBox("Enter A Positive integer value", "Input needed", "10")
Dim RetVal = Validation(UserInput)
If RetVal > -1 Then
IntegerList.Add(RetVal)
Else
MessageBox.Show("Please enter positive numbers only")
End If
End Sub
Function Validation(ByVal UserInput As String) As Integer
Dim ReturnInteger As Integer
If Integer.TryParse(UserInput, ReturnInteger) AndAlso ReturnInteger > -1 Then
Return ReturnInteger
Else
Return -1
End If
End Function
Private Sub DisplayTotal_Click(sender As Object, e As EventArgs) Handles DisplayTotal.Click
Dim Total = IntegerList.Sum
MessageBox.Show($"The Total is {Total}")
Dim LoopTotal As Integer
For Each i In IntegerList
LoopTotal += i
Next
MessageBox.Show($"The LoopTotal is {LoopTotal}")
End Sub
Note: The strings preceded by a $ are called interpolated strings. You can search for that term to learn how they work.

How do I get the textbox to enable after a certain amount of text is inputted?

So my next question(i know i know ive had a lot of questions already but im learning and my teachers suck)
but I am trying to get the textbox to go to readonly after a certain amount of text has been entered. I know how to make it a read only textbox but only after Ive had one set of data entered. i need it to be readonly after 7 days of data has been entered
I've tried inputtextbox.enabled = false
'Validating if user input is a number or not
Dim output As Integer
If Not Integer.TryParse(InputTextbox.Text, output) Then
MessageBox.Show("ERROR! Data must be a number")
InputTextbox.Text = String.Empty
Else
UnitsTextbox.AppendText(Environment.NewLine & InputTextbox.Text)
InputTextbox.Text = String.Empty
End If
InputTextbox.Enabled = False
I'm expecting it to disable after the user has entered 7 days worth of data but it only disables after one day of data is entered
Since the entries to UnitsTextbox are all done in code, this TextBox can be set to read only at design time.
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim output As Integer
If Not Integer.TryParse(InputTextbox.Text, output) Then
MessageBox.Show("ERROR! Data must be a number")
Else
UnitsTextbox.AppendText(Environment.NewLine & InputTextbox.Text)
End If
'Moved this line outside of the If because it happens either way
InputTextbox.Text = String.Empty
If UnitsTextbox.Lines.Length >= 7 Then
Button2.Enabled = False
End If
End Sub
Here's some simple psuedocode
Private Sub InvalidateTextbox(sender As TextBox, e As KeyEventArgs) Handles TextBox1.KeyUp, TextBox2.KeyUp
'FOR ANY TEXTBOX YOU WANT TO CONTROL WITH THIS SUB, ADD AN ADDITIONAL HANDLE.
If Strings.Len(sender.Text) > 7 Then
'^SIMPLE CONDITIONAL, CHECKING IF THE LENGTH IS MORE THAN SEVEN CHARACTERS, MODIFY THIS TO SUIT YOUR NEEDS.
sender.Enabled = False
'^IF THE CONDITIONAL IS TRUE, DEACTIVATE THE CONTROL, IF THAT IS WHAT YOU ARE LOOKING FOR.
sender.ReadOnly = true
'^IF YOU WANT READONLY,NOT ENABLED/DISABLED.
End If
End Sub
This code will execute every time a key is pressed while the text boxes are active. What is after "Handles" defines what events will trigger the sub.
sender becomes the textbox object that triggered the sub. e holds all the event arguments for the keyboard, so you can evaluate things like which key was pressed and other neat things.
There was some confusion on if you wanted enabled/disabled or readonly, both options included.

VB.net add line break after each loop

So I have been experimenting with VB.net (Windows Forms) to create a simple Ping Test app which pings the selected server and returns the elapsed time. I have declared a function to ping the address and then use a button to ping the server. The problem is that each time it pings, it only pings once and thus gives only one value. I would like to have a separate text box where the user enters the number of times they would like to ping the server for more accurate results.
Public Class Form1
Public Function Ping(ByVal server As String) As String
Dim s As New Stopwatch
s.Start()
My.Computer.Network.Ping(server)
s.Stop()
Return s.ElapsedMilliseconds.ToString
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim number As Integer = TextBox3.Text
For i = 1 To number
Try
TextBox1.Text = Ping(TextBox2.Text) & Environment.NewLine
Catch
MsgBox("Please enter a valid address", MsgBoxStyle.Critical, "Error")
End Try
Next
End Sub
End Class
I have tried using a loop to repeat the process and then return the results to a multi-line textbox for the user. Unfortunately it still only pings the address once and doesn't continue unless the ping button is clicked again, but then the first value is replaced by the next one. I believe the cause of the problem is that there should be a line break after each loop and I have tried using Enviroment.Newline but the problem persists. Any suggestions?
At the end I also would like to calculate the average ping of the results and expect to add all the ping values and divide by the number of times pinged. How would I get the results of the pings and add them?
Any help appreciated and excuse any spelling/grammatical errors.
In each loop you change the value of TextBox1 instead of appending the new value to the existing.
Optionally, you could also clear TextBox1 before starting the loop.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim number As Integer = TextBox3.Text
' Clear previous results
TextBox1.Text = String.Empty
For i = 1 To number
Try
' Append new result to existing ones
TextBox1.Text.AppendText(Ping(TextBox2.Text) & Environment.NewLine)
Catch
MsgBox("Please enter a valid address", MsgBoxStyle.Critical, "Error")
End Try
Next
End Sub

Sender and MessageBox oddities

New poster here and a VB hack of sorts.
I have a windows form that contains a picture box and three textboxes.
The three textboxes (Red, Green, Blue) are used to enter a numeric value from 000 to 255 representing a color code.
The PictureBox will display the resulting color from the three TextBox values.
My validation routine ValidDecCode makes sure the values entered are within the allowable limits (000-255).
If a user enters a ‘2’ in the first position all is well. If a user then enters a ‘6’ in the second position it will not pass my validation test.
After entering the KeyDown event I save the sender.selectionstart and the sender.text values. After entering the ‘6’ the selectionstart will be a 1 and text contains data that has been validated, ‘2’.
Once the ‘6’ fails my validation test I display a MessageBox, reload my saved sender data, text and selectionstart. This returns the form back to its state prior to entering the ‘6’. The TextBox will show a ‘2’ and the cursor is placed after the ‘2’.
What I find strange is that if I comment out the MessageBox.Show() line the TextBox will show ‘26’ after failing validation. If I comment out the reload of my sender data and not the MessageBox.Show() line, the TextBox will show ‘26’.
I would like to know why commenting out the MessageBox.Show() line does not return the form to its state prior to entering invalid data and what can I do about it. What is it about calling the MessageBox that makes it work?
Private Sub RedBox_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) _
Handles RedBox.KeyDown, GreenBox.KeyDown, BlueBox.KeyDown
Dim InChr As String
Dim InPos As Integer = sender.selectionstart
Dim InText As String = sender.text
If IsNumeric(Chr(e.KeyCode)) Then
InChr = Chr(e.KeyValue)
If Not ValidDecCode(InText + InChr, InPos) Then
MessageBox.Show("Invalid value")
sender.text = InText
sender.selectionstart = InPos
End If
Else
MessageBox.Show("Invalid value")
sender.Text = InText
sender.selectionstart = InPos
Exit Sub
End If
End Sub