Return false if char is repeated - vb.net

I'm coding in a DataGridView, and validating if the cell has a format of numbers and comma only, the cell is for document pages,
sample format that would return true, or accept: 1,2 or 1,2,5 BUT NOT 1,,2 or 1,,,6,2
I have made a function for that, and it works fine, BUT I'm not comfortable using my code, I hope there is a better code than I have.
Please correct my code for better.
Thanks.
Private Function isCELLPageNumb(ByRef valyo As String, ByVal origMaxPage As String) As Boolean
If valyo = "0" Or valyo = "," Then
valyo = origMaxPage
Return False
End If
Dim allowedChars As String = "0123456789,"
For i As Integer = (valyo.Length - 1) To 0 Step -1
If allowedChars.IndexOf(valyo(i)) = -1 Then
valyo = origMaxPage
Return False
End If
Try
If valyo(i) = "," Then
If valyo(i + 1) = "," Then
valyo = origMaxPage
Return False
End If
End If
Catch ex As Exception
valyo = origMaxPage
Return False
End Try
''I THINK I HAVE TO SEE IF THE COMMA NEXT NUMBER IS GREATER THAN THE MAXPAGE
''If valyo(i)>origMaxPage then
''End If
Next
Return True
End Function
Edited the origMaxPage
Private Function isCELLPageNumb(ByRef valyo As String, ByVal origMaxPage As String) As Boolean
If valyo = "0" Or valyo = "," Then
valyo = origMaxPage
Return False
End If
Dim allowedChars As String = "0123456789,"
For i As Integer = (valyo.Length - 1) To 0 Step -1
''IF ALLOWED CHARACTERS NOT IN THE INDEX
If allowedChars.IndexOf(valyo(i)) = -1 Then
valyo = origMaxPage
Return False
End If
Try
''IF VALYO IS COMMA REPEATED
If valyo(i) = "," Then
If valyo(i + 1) = "," Then
valyo = origMaxPage
Return False
End If
End If
Catch ex As Exception
valyo = origMaxPage
Return False
End Try
Try
''IF VALYO GREATHER THAN THE MAXPAGE
If valyo(i) = "," Then
Dim twodigit As String = valyo(i + 1) & valyo(i + 2)
Dim numtwodigit As UInt32 = Val(twodigit)
If numtwodigit > origMaxPage Then
valyo = origMaxPage
Return False
End If
End If
Catch ex As Exception
valyo = origMaxPage
Return False
End Try
Next
Return True
End Function
The problem of the code, what if the maxpage is 12, then the user inputed 1,3,5,1111
?
The input may NOT accept negative number like: -1 or -123
Thanks

I assume that at some point you're going to need to get the page numbers anyways, so you should start with that:
Public Function ParsePageNumbers(value As String, maxPage As Integer) As List(Of Integer)
Dim values As New List(Of Integer)()
For Each strNumber As var In value.Split(","C)
Dim intValue As Integer
' if it wasn't an integer or it's greater than the max page, restore the original value
If Not Integer.TryParse(strNumber, intValue) OrElse intValue > maxPage Then
Return Nothing
End If
values.Add(intValue)
Next
Return values
End Function
This function will return Nothing if the pages numbers have invalid values. Then in your actual method you can just call this method and check for Nothing:
Private Function isCELLPageNumb(ByRef valyo As String, ByVal origValue As String) As Boolean
Dim maxPage As Integer = Integer.Parse(origMaxPage)
' if it's not parsible, restore the original value
If ParsePageNumbers(value, maxPage) Is Nothing Then
value = origMaxPage
Return False
End If
' it was all valid
Return True
End Function

Combined to MackieChan solution to parse integer, you should use first Regex
private rgxNumberWithComma As New System.Text.RegularExpressions.Regex("^([0-9]+,?)+$")
Public Function CheckInput(ByVal valyo As String, _
ByVal origMaxPage As Integer) As Boolean
Dim match = rgxNumberWithComma.Match(valyo)
If Not match.Success Then
Return False
Else
Dim numbers as new List(Of Integer) ‘will store added numbers
For Each Item In valyo.Split(","c)
Dim intValue As Integer
‘Check if number is a valid integer
‘Check if number is 0
‘Check if number has already added the number list
‘Check if number is greater that MaxPage
If Not Integer.TryParse(Item, intValue) _
OrElse intValue > origMaxPage _
OrElse intValue = 0 _
OrElse numbers.Contains(IntValue) Then
Return False
Else
‘Item is valid, continue
Numbers.Add(intValue)
End If
Next
End If
Return True
End Function
See Need a Regex for comma separated number list

Try it in your Datagridview EditingControlShowing Event ...
Private Sub DataGridView1_EditingControlShowing(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles DataGridView1.EditingControlShowing
Try
If UCase(sCellName) = "PAGENUM" '------> change this with yours
AddHandler e.Control.KeyPress, AddressOf PageKeypress
End If
Catch ex As Exception
'...
End Try
End Sub
Private Sub PageKeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs)
Static sLast As String = ""
Dim k As Byte = Asc(e.KeyChar)
Dim sN As String = "0123456789,"
Dim sO As String = Chr(8) & Chr(13) & Chr(1) & Chr(3) & Chr(22)
Dim nMaxPage As Integer = 12 '-------change this with yours
If Not (sN & sO).Contains(e.KeyChar) Then
e.Handled = True
Else
Select Case e.KeyChar
Case ","
If sLast = "," Then
e.Handled = True
Else
e.Handled = False
sLast = ","
End If
Exit Sub
Case "0"
If sLast = "," Or sLast = "" Then
e.Handled = True
Exit Sub
End If
Case Chr(13) '-- avoid "," in end of text OR YOU CAN REMOVE THIS
If sLast = "," Then e.Handled = True
End Select
If sLast = "," Then sLast = ""
If Val(sLast & e.KeyChar) > nMaxPage Then
e.Handled = True
Exit Sub
End If
sLast &= IIf(sN.Contains(e.KeyChar), e.KeyChar, "")
End If
End Sub

Related

Event not Firing on First KeyPress

I am trying to call a Sub from within the keyPress event in a textBox, the problem is that the Sub will not get called until the second keyPress, at that time the keyPress processes the first key entered, if a third keyPress is done the sub will process the second keyPress and so on... Here is an image;
And here is my code;
Private nonNumberEntered As Boolean = False
Private Sub txtAmount_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles txtAmount.KeyPress
'Only allowed characters
Dim allowedChars As String = "0123456789."
nonNumberEntered = False
If Char.IsDigit(e.KeyChar) = False And Char.IsControl(e.KeyChar) = False Then
If e.KeyChar <> ControlChars.Back Then
If allowedChars.IndexOf(e.KeyChar) = -1 Then
' Invalid Character, notify clear and return
MsgBox("Numbers only", MsgBoxStyle.Exclamation)
txtAmount.Text = ""
txtAmount.Focus()
nonNumberEntered = True
End If
End If
End If
'If shift key was pressed, it's not a number.
If Control.ModifierKeys = Keys.Shift Then
nonNumberEntered = True
End If
'Call the function to create a text line out of the numbers
'Regex to ensure the string contains numbers
Dim re As New Text.RegularExpressions.Regex("\d")
If re.IsMatch(txtAmount.Text) Then
If nonNumberEntered = False Then
Dim newNum = txtAmount.Text.Trim
'If there are any leading weird . in the string
newNum = newNum.TrimStart(".")
Dim newStr As String
'Build the array
Dim newDec As String() = newNum.Split(New Char() {"."c})
If newNum.Contains(".") Then
newStr = NumberToText(newDec(0))
lblResult.Text = newStr & " Dollars and " & newDec(1) & "/100 "
Else
newStr = NumberToText(newDec(0))
lblResult.Text = newStr & " Dollars and 00/100 "
End If
End If
End If
End Sub
Any ideas?
As #jmcilhinney alluded in the comments, you are trying to do too much in the KeyPress event handler. That handler should only be used to allow valid key presses and suppress invalid key presses. Whenever a valid key press is made, it is allowed to go through and then the TextChanged event handler will be called. Setting e.Handled = True will suppress the key press and the TextChanged event will not be called.
Private Sub txtAmount_KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox2.KeyPress
'Only allowed characters
Dim allowedChars As String = "0123456789."
If Char.IsDigit(e.KeyChar) = False And Char.IsControl(e.KeyChar) = False Then
If e.KeyChar <> ControlChars.Back Then
If allowedChars.IndexOf(e.KeyChar) = -1 Then
' Invalid Character, notify clear and return
e.Handled = True 'Set to True to 'swallow' the keypress and prevent the TextChanged event from firing.
MsgBox("Numbers only", MsgBoxStyle.Exclamation)
txtAmount.Text = ""
txtAmount.Focus()
End If
End If
End If
End Sub
Private Sub txtAmount_TextChanged(sender As Object, e As EventArgs) Handles TextBox2.TextChanged
lblResult.Text = NumberToText(txtAmount.Text)
End Sub
Public Function NumberToText(input As String) As String
'Convert value of amount to words here
End Function
You may also wish to look into using a MaskedTextBox which will handle the validation automatically.
Here is what I am using as my solution, might be a bit of a kluge but it works;
Private nonNumberEntered As Boolean = False
Private Sub txtAmount_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txtAmount.KeyPress
'Only allowed characters
Dim allowedChars As String = "0123456789."
If Char.IsDigit(e.KeyChar) = False And Char.IsControl(e.KeyChar) = False Then
If e.KeyChar <> ControlChars.Back Then
If allowedChars.IndexOf(e.KeyChar) = -1 Then
' Invalid Character, notify clear and return
nonNumberEntered = True 'Set to True to 'swallow' the keypress and prevent the TextChanged event from firing.
MsgBox("Numbers only", MsgBoxStyle.Exclamation)
txtAmount.Text = ""
txtAmount.Focus()
lblResult.Text = ""
End If
End If
End If
'If shift key was pressed, it's not a number.
If Control.ModifierKeys = Keys.Shift Then
nonNumberEntered = True
txtAmount.Text = ""
txtAmount.Focus()
End If
End Sub
Private Sub txtAmount_TextChanged(sender As Object, e As EventArgs) Handles txtAmount.TextChanged
'Call the function to create a text line out of the numbers
'Regex to ensure the string contains numbers
Dim t As TextBox = sender
Dim foo As Decimal
If Decimal.TryParse(txtAmount.Text, foo) Then
'data is good
Dim re As New Text.RegularExpressions.Regex("\d")
If re.IsMatch(txtAmount.Text) Then
If nonNumberEntered = False Then
Dim newNum = txtAmount.Text.Trim
'If there are any leading weird . in the string
newNum = newNum.TrimStart(".")
Dim newStr As String
'Build the array
Dim newDec As String() = newNum.Split(New Char() {"."c})
If newNum.Contains(".") Then
newStr = NumberToText(newDec(0))
lblResult.Text = newStr & " Dollars and " & newDec(1) & "/100 "
Else
newStr = NumberToText(newDec(0))
lblResult.Text = newStr & " Dollars and 00/100 "
End If
End If
End If
Else
'data is bad
nonNumberEntered = False
txtAmount.Text = ""
txtAmount.Focus()
lblResult.Text = ""
End If
End Sub
Note that in the textChanged I am checking to see if the value is actually a number, if ot, clear contents and keep going. In textChanged I also allow a decimal point, but nothing else, and then I clear everything making the user start over. Simple, yet effective......
Ok Chris, you were close. What I needed to do was set e.KeyChar = "" and then trap the and in KeyPress. So here is my final solution that is working as intended.
Private Sub cbCheckAmount_KeyPress(sender As Object, e As KeyPressEventArgs) Handles cbCheckAmount.KeyPress
'Only allowed characters
Dim allowedChars As String = "0123456789."
If Char.IsDigit(e.KeyChar) = False And Char.IsControl(e.KeyChar) = False Then
If e.KeyChar <> ChrW(Keys.Return) Or e.KeyChar <> ChrW(Keys.Tab) Then
If e.KeyChar <> ControlChars.Back Or e.KeyChar <> ControlChars.Tab Then
If allowedChars.IndexOf(e.KeyChar) = -1 Then
' Invalid Character, notify clear and return
nonNumberEntered = True 'Set to True to 'swallow' the keypress and prevent the TextChanged event from firing.
MsgBox("Numbers only", MsgBoxStyle.Exclamation)
cbCheckAmount.Text = ""
cbCheckAmount.Focus()
lblTotalText.Text = ""
e.KeyChar = ""
nonNumberEntered = False
End If
End If
End If
End If
'If shift key was pressed, it's not a number.
If Control.ModifierKeys = Keys.Shift Then
nonNumberEntered = True
cbCheckAmount.Text = ""
cbCheckAmount.Focus()
End If
End Sub
Private Sub cbCheckAmount_TextChanged(sender As Object, e As EventArgs) Handles cbCheckAmount.TextChanged
'Call the function to create a text line out of the numbers
'Regex to ensure the string contains numbers
Dim t As ComboBox = sender
Dim foo As Decimal
If nonNumberEntered = False Then
If Decimal.TryParse(cbCheckAmount.Text, foo) Then
'data is good
Dim re As New Text.RegularExpressions.Regex("\d")
If re.IsMatch(cbCheckAmount.Text) Then
If nonNumberEntered = False Then
Dim newNum = cbCheckAmount.Text.Trim
'If there are any leading weird . in the string
newNum = newNum.TrimStart(".")
Dim newStr As String
'Build the array
Dim newDec As String() = newNum.Split(New Char() {"."c})
If newNum.Contains(".") Then
newStr = NumberToText(newDec(0))
lblTotalText.Text = newStr & " Dollars and " & newDec(1) & "/100 "
Else
newStr = NumberToText(newDec(0))
lblTotalText.Text = newStr & " Dollars and 00/100 "
End If
End If
End If
End If
Else
'data is bad
nonNumberEntered = True
cbCheckAmount.Text = ""
'cbCheckAmount.Focus()
'lblTotalText.Text = ""
End If
End Sub

multi-threaded code to check proxies

I'm suffering with this VB.Net 2017 code which is supposed to check if Proxies working or not. Sometimes it reach to an end successfully, and sometimes the program never reach and end or take lots of time to do so, although I have specified the timeout for every webrequest to be 11000... Also, the list of working proxies always has duplicates! I don't know how that happens, althoug the original (raw) list is unique!
Could you please help? This is supposed to wait till the 99 threads finished then another 99 (or the remaining threads) kick-started.
P.S. MYWEBSITE.com works for me only and it displays the IP address of the visitor, i.e. to double check if the proxy has worked fine
Imports System.Net
Imports System.IO
Imports System
Imports System.Text.RegularExpressions
Imports System.Threading
Public Class frmMain
Dim FinalWorkingProxies As New List(Of String)()
Private Sub btnBrowse_Click(sender As Object, e As EventArgs) Handles btnBrowse.Click
Control.CheckForIllegalCrossThreadCalls = False
PB.Maximum = txtRawIP.Lines.Count
PB.Value = 0
StartCheckingIP(0)
End Sub
Function StartCheckingIP(ByVal num As Integer)
For I As Integer = num To txtRawIP.Lines.Count - 1
Dim StrIPOnly As String = txtRawIP.Lines(I)
StrIPOnly = Trim(StrIPOnly.TrimStart("0"c)) 'remove any leading zeros
Try
Dim clsThreads As New System.Threading.Thread(AddressOf CheckIP)
clsThreads.Start(StrIPOnly)
Catch ex As Exception
MsgBox(I)
End Try
If (I > 0 And (I Mod 99 = 0)) Then Exit For
Next
Return True
End Function
Private Function CheckIP(ByVal Prox As String) As Boolean
'txtHTML.Text += vbCrLf & Prox
'txtHTML.Refresh()
Dim txtWebResult As String = ""
Dim OriginalFullProx As String = Trim(Prox)
Dim proxyObject As WebProxy = New WebProxy("http://" & OriginalFullProx & "/")
proxyObject.BypassProxyOnLocal = True
Prox = Prox.Substring(0, Prox.IndexOf(":"))
Dim sURL As String
sURL = "http://MYWEBSITE.com/testip.php"
Dim wrGETURL As WebRequest
wrGETURL = WebRequest.Create(sURL)
wrGETURL.Proxy = proxyObject
wrGETURL.Timeout = 6000
txtWebResult = "Dosn't work"
Try
Dim objStream As Stream
objStream = wrGETURL.GetResponse.GetResponseStream
Dim objReader As New StreamReader(objStream)
Dim sLine As String = ""
sLine = objReader.ReadLine
If Not sLine Is Nothing Then
txtWebResult = sLine
End If
txtWebResult = Regex.Replace(txtWebResult, “^\s+$[\r\n]*”, “”, RegexOptions.Multiline)
If (Trim(Prox) = Trim(txtWebResult)) Then
FinalWorkingProxies.Add(OriginalFullProx)
End If
Catch ex As Exception
txtWebResult = "Dosn't work"
End Try
If (PB.Value < PB.Maximum) Then PB.Value += 1
PB.Refresh()
If (PB.Value = PB.Maximum) Then
txtFilteredIP.Clear()
Randomize()
Dim RRR As Integer = CInt(Math.Ceiling(Rnd() * 1000)) + 1
Thread.Sleep(RRR)
If (txtFilteredIP.Text <> "") Then Return False
Dim str As String
For Each str In FinalWorkingProxies
txtFilteredIP.Text += str & vbCrLf
Next
ElseIf ((PB.Value - 1) > 0 And ((PB.Value - 1) Mod 99 = 0)) Then
StartCheckingIP(PB.Value)
End If
Return True
End Function
Private Sub txtRawIP_TextChanged(sender As Object, e As EventArgs) Handles txtRawIP.TextChanged
lblRawIPTotal.Text = "Total: " & txtRawIP.Lines.Count
End Sub
Private Sub txtFilteredIP_TextChanged(sender As Object, e As EventArgs) Handles txtFilteredIP.TextChanged
lblFilteredIPTotal.Text = "Total: " & txtFilteredIP.Lines.Count
End Sub
End Class
Here is the modified code, but it stills takes long of time to finalize long list of proxies, although I sat max concurrent connection to 2000 and timeout to 8sec. Please help. Thanks.
Public Class frmMain
Dim FinalWorkingProxies As New List(Of String)()
Private Sub btnBrowse_Click(sender As Object, e As EventArgs) Handles btnBrowse.Click
'Control.CheckForIllegalCrossThreadCalls = False
ServicePointManager.Expect100Continue = False
ServicePointManager.DefaultConnectionLimit = 2000
'ServicePointManager.Expect100Continue = True
FinalWorkingProxies.Clear()
PB.Maximum = txtRawIP.Lines.Count
PB.Value = 0
StartCheckingIP(0)
End Sub
Function StartCheckingIP(ByVal num As Integer)
For I As Integer = num To txtRawIP.Lines.Count - 1
Dim StrIPOnly As String = txtRawIP.Lines(I)
StrIPOnly = Trim(StrIPOnly.TrimStart("0"c)) 'remove any leading zeros
Try
Dim clsThreads As New System.Threading.Thread(AddressOf CheckIP)
clsThreads.Start(StrIPOnly)
Catch ex As Exception
MsgBox(I)
End Try
If (I > 0 And (I Mod 333 = 0)) Then Exit For
Next
Return True
End Function
Private Function CheckIP(ByVal Prox As String) As Boolean
'txtHTML.Text += vbCrLf & Prox
'txtHTML.Refresh()
Dim txtWebResult As String = ""
Dim OriginalFullProx As String = Trim(Prox)
Dim proxyObject As WebProxy = New WebProxy("http://" & OriginalFullProx & "/")
proxyObject.BypassProxyOnLocal = True
Prox = Prox.Substring(0, Prox.IndexOf(":"))
Dim sURL As String
sURL = "http://MYWEBSITE.com/testip.php"
Dim wrGETURL As WebRequest
wrGETURL = WebRequest.Create(sURL)
wrGETURL.Proxy = proxyObject
wrGETURL.Timeout = 8000
txtWebResult = "Dosn't work"
Try
Dim objStream As Stream
objStream = wrGETURL.GetResponse.GetResponseStream
Dim objReader As New StreamReader(objStream)
Dim sLine As String = ""
sLine = objReader.ReadLine
If Not sLine Is Nothing Then
txtWebResult = sLine
End If
txtWebResult = Regex.Replace(txtWebResult, “^\s+$[\r\n]*”, “”, RegexOptions.Multiline)
If (Trim(Prox) = Trim(txtWebResult)) Then
'Now know exact country
sURL = "http://ip-api.com/xml/" & Prox
wrGETURL = WebRequest.Create(sURL)
wrGETURL.Proxy = proxyObject
wrGETURL.Timeout = 8000
objStream = wrGETURL.GetResponse.GetResponseStream
Dim objReader2 As New StreamReader(objStream)
Dim FullCODEOFAPI As String = objReader2.ReadToEnd()
Dim XMLR As XmlReader
XMLR = XmlReader.Create(New StringReader(FullCODEOFAPI))
XMLR.ReadToFollowing("country")
XMLR.Read()
OriginalFullProx += "-" + XMLR.Value
FinalWorkingProxies.Add(OriginalFullProx)
End If
Catch ex As Exception
txtWebResult = "Dosn't work"
End Try
If (PB.Value < PB.Maximum) Then UpdatePB(1)
If (PB.Value = PB.Maximum) Then
UpdateFilteredList(1)
ElseIf ((PB.Value - 1) > 0 And ((PB.Value - 1) Mod 333 = 0)) Then
StartCheckingIP(PB.Value)
End If
Return True
End Function
Private Delegate Sub UpdatePBDelegate(ByVal PBVal As Integer)
Private Sub UpdatePB(ByVal PBVal As Integer)
If PB.InvokeRequired Then
PB.Invoke(New UpdatePBDelegate(AddressOf UpdatePB), New Object() {PBVal})
Else
PB.Value += PBVal
PB.Refresh()
End If
End Sub
Private Delegate Sub UpdateFilteredListDelegate()
Private Sub UpdateFilteredList(ByVal TMP As Integer)
If txtFilteredIP.InvokeRequired Then
txtFilteredIP.Invoke(New UpdatePBDelegate(AddressOf UpdateFilteredList), New Object() {TMP})
Else
txtFilteredIP.Clear()
Dim str As String
For Each str In FinalWorkingProxies
txtFilteredIP.Text += str & vbCrLf
Next
End If
End Sub
Private Sub txtRawIP_TextChanged(sender As Object, e As EventArgs) Handles txtRawIP.TextChanged
lblRawIPTotal.Text = "Total: " & txtRawIP.Lines.Count
End Sub
Private Sub txtFilteredIP_TextChanged(sender As Object, e As EventArgs) Handles txtFilteredIP.TextChanged
lblFilteredIPTotal.Text = "Total: " & txtFilteredIP.Lines.Count
End Sub
Private Sub btnLoadList_Click(sender As Object, e As EventArgs) Handles btnLoadList.Click
OFD.ShowDialog()
If (OFD.FileName <> "") Then
txtRawIP.Text = File.ReadAllText(OFD.FileName)
End If
End Sub
End Class

(VB.NET) Object reference not set to an instance of an object

This program works like this: User enters building name and number of floors, that gets validated and accepted. Then user enters rates for each floor until it goes through all floors, that data gets added to a listbox, then user enters a desired floor and it adds the rent and other info to another listbox lower down. As soon as I enter my number of floors and click on the button to save the info, the program runs into an error under btnEnterBuilding Click event where it says dblRates(intHowMany) = dblRent. The error is
"An unhandled exception of type 'System.NullReferenceException' occurred in WindowsApplication5.exe
Additional information: Object reference not set to an instance of an object."
Any help would be greatly appreciated, thanks!
Option Explicit On
Option Strict On
Option Infer Off
Public Class Form1
Dim dblRates() As Double
Dim intHowMany As Integer = 0 'points to the next avail entry in the array
Private Function ValidateString(ByVal strText As String, strInput As String, strValue As String) As Boolean
If strText = Nothing Then
MessageBox.Show(strText & " Must Be Supplied", "Error")
Return False
Else
Return True
End If
End Function
Private Function ValidateInteger(ByVal strText As String,
ByVal strIn As String,
ByRef intValue As Integer,
ByVal intMinValue As Integer,
ByVal intMaxValue As Integer) As Boolean
If strIn = Nothing Then
MessageBox.Show(strText & " Must Be Supplied", "Error")
Return False
Else
If Integer.TryParse(strIn, intValue) = False Then
MessageBox.Show(strText & " Must Be A Whole Number", "Error")
Return False
Else
If intValue < intMinValue Or intValue > intMaxValue Then
MessageBox.Show("Outside of Number of " & strText & " Limits", "Error")
Return False
Else
Return True
End If
End If
End If
End Function
Private Function ValidateDouble(ByVal strText As String,
ByVal strDbl As String,
ByRef dblValue As Double,
ByVal dblMinValue As Double,
ByVal dblMaxValue As Double) As Boolean
If strDbl = Nothing Then
MessageBox.Show(strText & " Must Be Supplied", "Error")
Return False
Else
If Double.TryParse(strDbl, dblValue) = False Then
MessageBox.Show(strText & " Must Be A Whole Number", "Error")
Return False
Else
If dblValue < dblMinValue Or dblValue > dblMaxValue Then
MessageBox.Show("Outside of Number of " & strText & " Limits", "Error")
Return False
Else
Return True
End If
End If
End If
End Function
Private Sub Form1_Load(sender As Object,
e As EventArgs) Handles Me.Load
Me.grpBuilding.Enabled = True
Me.grpRents.Enabled = False
Me.grpDesiredFloor.Enabled = False
End Sub
Private Sub btnRents_Click(sender As Object,
e As EventArgs) _
Handles btnRents.Click
Dim strName, strFloors As String
Dim intFloors As Integer
strName = txtName.Text
strFloors = txtFloors.Text
intFloors = CInt(strFloors)
If ValidateString("Building name", Me.txtName.Text, strName) = True Then
If ValidateInteger("Number of floors", Me.txtFloors.Text, intFloors, 3, 20) = True Then
Me.grpBuilding.Enabled = False
Me.grpRents.Enabled = True
Me.grpDesiredFloor.Enabled = False
End If
End If
End Sub
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
Close()
End Sub
Private Sub btnEnterBuilding_Click(sender As Object,
e As EventArgs) _
Handles btnEnterBuilding.Click
Dim intFloors As Integer
Dim dblRent As Double
Dim strRent As String
strRent = txtRent.Text
dblRent = CDbl(strRent)
If ValidateDouble("Rent", Me.txtRent.Text, dblRent, 1000.0, 2500.0) = True Then
dblRates(intHowMany) = dblRent
Me.txtRent.Focus()
Me.txtRent.SelectAll()
Me.ListBox1.Items.Add("Floor No. " & intHowMany.ToString("N0") &
" -- Rent Is: " & dblRent.ToString("N$"))
If intHowMany < intFloors Then
intHowMany += 1
Else
Me.grpBuilding.Enabled = False
Me.grpRents.Enabled = False
Me.grpDesiredFloor.Enabled = True
End If
Else
Me.txtRent.Focus()
Me.txtRent.SelectAll()
End If
End Sub
Private Sub btnCompute_Click(sender As Object, e As EventArgs) Handles btnCompute.Click
Dim intFloors, intFloor As Integer
Dim strName, strFloors As String
strName = txtName.Text
strFloors = txtFloors.Text
intFloors = CInt(strFloors)
If ValidateInteger("Desired Floor", Me.txtFloor.Text, intFloor, 3, 20) = False Then
MessageBox.Show("Please enter a valid floor number", "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error)
Else
Me.lstDisplay.Items.Add("Building Name: " & strName & " # of Floors: " & intFloors.ToString)
Me.lstDisplay.Items.Add("Desired Floor: " & intFloor.ToString)
Me.lstDisplay.Items.Add(" Rent: " & intFloors.ToString)
End If
End Sub
End Class
You can't dim dblRates() as double like this without giving it initial values. You will need to dim dblRates(<some amount>) as Double and then redim it if necessary to add more values to it. Or you could Dim dblRates() as double = {0} but if you still want to add more values to the array, you will still need to redim it as the second options would just create an array of 1 element.

VB.NET validate the form to check if empty fields or errors exists

So far I have written code to remain Save&Update buttons disabled until user fills all required fields(Textboxes & Comboboxes) in Groupbox, but I also want the Save&Update buttons to remain disabled until user has addressed all errors available in the form e.g Book_Name should not go beyond 50 characters!
I would really appreciate if someone help me in this!
Below is the code that I tried to do so what I have mentioned above but somehow it is not working:
Private Sub ValidateInputs(ByVal Sender As Object, ByVal e As EventArgs)
Dim ctrl As Control
Dim strErrorList As String
strErrorList = ""
For Each ctrl In Me.Controls
If Len(ErrorProvider1.GetError(ctrl)) > 0 Then
strErrorList += ErrorProvider1.GetError(ctrl) & ChrW(10) &
ChrW(13)
End If
Next
If Len(strErrorList) = 0 Then
' Process stuff if no errors
btnsave.Enabled = Not GroupBox1.Controls.OfType(Of TextBox).Any(Function(t) t.Text = String.Empty) And _
Not (cboStaff_id.Text = String.Empty OrElse cboPub_id.Text = String.Empty OrElse cboSub_Code.Text = String.Empty _
OrElse DateTimePicker1.Text = " ")
btnSaveUpdate.Enabled = Not GroupBox1.Controls.OfType(Of ComboBox).Any(Function(cbo) cbo.Text = String.Empty) And _
Not (txtbook_name.Text = String.Empty OrElse txtauthor.Text = String.Empty OrElse txtprice.Text = String.Empty _
OrElse txtrack_no.Text = String.Empty OrElse TxtNo_of_Books.Text = String.Empty OrElse txtvol_no.Text = String.Empty OrElse DateTimePicker1.Text = " ")
btndelete.Enabled = Not (cboISBN.Text = String.Empty)
Else
btnsave.Enabled = False
btnSaveUpdate.Enabled = False
MessageBox.Show(strErrorList, "List Of Errors")
End If
End Sub
Use Error Providers Or Create your own error provider that does the task required for you and for the ISBN textBox say put the MaxLength=13 it will do the task without any error providers or validators, For phone number of email use masked text box, or handle the text change event of the textbox if you want to accept only numbers in that textbox
Since I asked the question 4 days ago and no one provided an answer to solve my problem, I researched & rechecked my code and found solution for my problem!
So I am gonna explain each point to clarify what I have done.
'Below disables numeric entry; only characters and spaces allowed with the help of ASCII values
Private Sub txtbook_name_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txtbook_name.KeyPress
If Not (Asc(e.KeyChar) = 8) Then
If Not ((Asc(e.KeyChar) >= 97 And Asc(e.KeyChar) <= 122) _ Or (Asc(e.KeyChar) >= 65 _
And Asc(e.KeyChar) <= 90) _
Or (Asc(e.KeyChar) = 32)) Then
e.KeyChar = ChrW(0)
e.Handled = True
End If
End If
End Sub
'Bellow function return only true if input matches Regex pattern in other cases false
Private Function ValidBook_name(ByVal book_name As String, ByRef errorMessage As String) As Boolean
Dim regex As New System.Text.RegularExpressions.Regex("^[a-zA-Z ]{1,50}$")
' Confirm there is text in the control.
If txtbook_name.Text.Length = 0 Then
errorMessage = "Book Name is required"
Return False
End If
If txtbook_name.Text.Length > 50 Then
errorMessage = "Book Name can not be more than 50"
Return False
End If
'Confirm that book name is in character not number
If (regex.IsMatch(Trim(txtbook_name.Text))) Then
errorMessage = ""
Return True
End If
errorMessage = "A valid Book Name is required" + ControlChars.Cr
Return False
End Function
'Check whether input entered is valid or not; if not return cursor to control
Private Sub txtbook_name_Validating(ByVal sender As Object, _
ByVal e As System.ComponentModel.CancelEventArgs) Handles txtbook_name.Validating
Dim errorMsg As String
Try
If Not ValidBook_name(txtbook_name.Text, errorMsg) Then
' Cancel the event and select the text to be corrected by the user.
e.Cancel = True
txtbook_name.Select(0, txtbook_name.Text.Length)
' Set the ErrorProvider error with the text to display.
Me.ErrorProvider1.SetError(txtbook_name, errorMsg)
End If
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Private Sub txtbook_name_Validated(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles txtbook_name.Validated
' If all conditions have been met, clear the error provider of errors.
Try
ErrorProvider1.SetError(txtbook_name, "")
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Hope this helps...

Textbox validation for alphabetical and alphanumeric textbox with "."

This is what i am using but i want to include "." dot also as an input in the textbox
If Char.IsLetter(e.KeyChar) = False Then
If e.KeyChar = CChar(ChrW(Keys.Back)) or e.KeyChar = CChar(ChrW(Keys.Space)) Then
e.Handled = False
Else
e.Handled = True
End If
End If
and
If Char.IsLetterOrDigit(e.KeyChar) = False Then
If e.KeyChar = CChar(ChrW(Keys.Back)) or e.KeyChar = CChar(ChrW(Keys.Space)) Then
e.Handled = False
Else
e.Handled = True
End If
End If
To include a period in the list of valid characters, use an OrElse term to test for multiple conditions. Note that "." is a String, different to "."c which is a Char.
If Not (Char.IsLetterOrDigit(e.KeyChar) OrElse e.KeyChar = "."c) Then
If e.KeyChar = CChar(ChrW(Keys.Back)) or e.KeyChar = CChar(ChrW(Keys.Space)) Then
e.Handled = False
Else
e.Handled = True
End If
End If
You could just use ASCII code
If Asc(C$(F1)) > 122 Or Asc(C$(F1)) < 97 And Asc(C$(F1)) > 90 Or Asc(C$(F1)) < 65 And Asc(C$(F1)) > 57 Or Asc(C$(F1)) < 48 Then
Label9.Text = C$(F1) + " is an invalid Charater!"
End If
For a single character you can just do Or variable =".". ASCII works when you want a range.
The code snippet is from Numeric Base conversion program check for invalid charters in a number, which will convert any base from 2 to 36. And, with minor tweaking will work in any form of BASIC including Applesoft (tweak no end if, and all on one line, label9.text becomes a text varible) which can also be done in VB.
You can use my control:
''' <summary>
''' By Amen Ayach
''' Use RoundNumber property to set how many decimal after "."
''' example: RoundNumber = 3 so if you write 654.4444 so onlostFocus you'll see 654.444
''' </summary>
''' <remarks></remarks>
Public Class TBRound
Inherits TextBox
Dim Enterly As Boolean = True
Private _RoundNumber As Integer = 0
Public Property RoundNumber() As Integer
Get
Return _RoundNumber
End Get
Set(ByVal value As Integer)
_RoundNumber = value
End Set
End Property
Public Overrides Property Text() As String
Get
Return MyBase.Text
End Get
Set(ByVal value As String)
MyBase.Text = value
End Set
End Property
Public Function format_Number(ByVal nb As String, ByVal isDivided As Boolean, ByVal NumberAfterComma As Integer) As String
Dim str As String = ""
Try
Dim fromatString As String = ""
Dim nbs As String = "."
For i As Integer = 0 To NumberAfterComma - 1
nbs += "0"
Next
If isDivided Then
str = "#,###"
Else
str = "#"
End If
str += nbs
str = Format(Val(Decimal.Parse(nb.ToString())), str)
Catch
End Try
Return str
End Function
Private Sub TBRound_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles Me.KeyPress
Dim allow As String = "0123456789." + ChrW(Keys.Back) + ChrW(Keys.Delete)
If Not allow.Contains(e.KeyChar) Then
e.Handled = True
End If
End Sub
Private Sub TBRound_LostFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.LostFocus, Me.Validated
Try
If Not Decimal.TryParse(MyBase.Text, New Decimal) Then
MyBase.Text = "0"
Else
ValDateMe()
End If
Catch
End Try
End Sub
Private Sub ValDateMe()
Try
Dim value = MyBase.Text
If Decimal.TryParse(MyBase.Text, New Decimal) Then
If MyBase.Text <> format_Number(MyBase.Text, False, RoundNumber) Then
MyBase.Text = format_Number(MyBase.Text, False, RoundNumber)
End If
Else
Enterly = False
MyBase.Text = "0"
Enterly = True
End If
Catch
End Try
End Sub
End Class
You can use the following function:
Private Function StripInput(sender As String) As String
If sender <> String.Empty Then
Dim lastChr As String = sender(sender.Length - 1)
Dim stripList As String = "`¬!""£$%^&*()_+-=}{[]}~##'':?/>.<,|\;"
If stripList.Contains(lastChr) Then
Return sender.Substring(0, sender.Length - 1)
Else
Return sender
End If
Else
Return sender
End If
End Function
and call it from the TextChanged handler of the text box with :
sender.text = StripInput(sender.text)
sender.SelectionStart = sender.Text.Length + 1
And if you want to include any character, simply remove it from the strip list.