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

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.

Related

Why is this variable constantly resetting?

I'm working on a program in VB.net that uses the form load event to prompt for password. I have this working, but I am supposed to be showing the attempt number you are at if you fail. However, my code is always returning "Attempt #1" and never increasing to #2, #3, etc, and I am unsure why it is constantly being reset.
Private Function checkPassword(passwordGuess As String)
Dim isValid As Boolean = False
Dim password As String = "941206"
Dim attemptCounter As Integer
If isValid = False Then
If password <> txtPassword.Text Then
attemptCounter += 1
MessageBox.Show("Login Unsuccesful.",
"Attempt #" & attemptCounter)
Else
isValid = True
MessageBox.Show("Login Successful.",
"Attempt #" & attemptCounter)
Me.Text = "Attempt #" & attemptCounter
End If
End If
End Function
Private Sub btnConfirm_Click(sender As Object, e As EventArgs) Handles btnConfirm.Click
Dim password As String
password = txtPassword.Text
checkPassword(password)
End Sub
You could create a class to store information about attempts that persists across function calls:
Public Class attempt
Public Shared counter As Integer = 0
End Class
Private Function checkPassword(passwordGuess As String)
Dim isValid As Boolean = False
Dim password As String = "941206"
If isValid = False Then
If password <> txtPassword.Text Then
attempt.counter += 1
MessageBox.Show("Login Unsuccesful.",
"Attempt #" & attempt.counter)
Else
isValid = True
MessageBox.Show("Login Successful.",
"Attempt #" & attempt.counter)
Me.Text = "Attempt #" & attempt.counter
End If
End If
End Function
Private Sub btnConfirm_Click(sender As Object, e As EventArgs) Handles btnConfirm.Click
Dim password As String
password = txtPassword.Text
checkPassword(password)
End Sub

Reading lines from a text file in VB

I'm creating a Quiz Application in VB and the quiz app reads the questions from a text file which is already created and it has got some questions in it.
1
Q.Who won the WorldCup last time?
I Don't know
May be he knows
Who knows
Who cares?
2
Question 2
Answer A
Answer B
Answer C
Answer D
3
Question 3
Ans 1
Ans 2
Ans 3
Ans 4
The first line is the question number,the second line is the question,lines 3 - 6 represents the answer choices.Now I have created a Form for quiz and when the next button is pressed it should display the next question i.e,After the first question it should go to Question 2 and print accordingly.But unfortunately i'm unable to calculate the logic to go to next question.
Public Class Quiz
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As Integer, ByVal lParam As Integer) As IntPtr
End Function
Dim SCORE As Integer = 0
Dim val As Integer = 30
Dim QUES As Integer = 0
Dim Line As Integer = 1
Dim allLines As List(Of String) = New List(Of String)
Dim TextFilePath As String = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Quiz.txt")
Private Sub Quiz_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ProgressBar1.Minimum = 0
ProgressBar1.Maximum = 30
Timer1.Enabled = True
Next_Prev_Ques(Line + QUES)
End Sub
Public Function Next_Prev_Ques(quesno As Integer) As Integer
Line = quesno
Using file As New System.IO.StreamReader(TextFilePath)
Do While Not file.EndOfStream
allLines.Add(file.ReadLine())
Loop
End Using
QUES = ReadLine(Line, allLines)
Label1.Text = ReadLine(Line + 1, allLines)
RadioButton1.Text = ReadLine(Line + 2, allLines)
RadioButton2.Text = ReadLine(Line + 3, allLines)
RadioButton3.Text = ReadLine(Line + 4, allLines)
RadioButton4.Text = ReadLine(Line + 5, allLines)
Return Line
End Function
Public Function ReadLine(lineNumber As Integer, lines As List(Of String)) As String
Return lines(lineNumber - 1)
End Function
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
ProgressBar1.Value += 1
val -= 1
Label2.Text = val & " Sec"
If ProgressBar1.Value = ProgressBar1.Maximum Then
Timer1.Enabled = False
End If
If ProgressBar1.Value > 25 Then
SendMessage(ProgressBar1.Handle, 1040, 2, 0)
End If
End Sub
Private Sub Quiz_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
Form1.Close()
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
MsgBox(Line + QUES + 5)
Next_Prev_Ques(Line + QUES + 4)
Me.Refresh()
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Next_Prev_Ques(Line + QUES + 5)
End Sub
The function Next_Prev_Ques Should run accordingly but its not.Can anyone post the correct code?
Below is some code that uses serialization to get the same results. You can create a class called Questions and properties on it like questionnumber, question and answer, store the data into a xml file and retrieve them with string methods. Check the code below:
The code for the class
Public Class clsQuestions
Private _Number As String
Private _Question As String
Private _Answer As String
Public Property Number() As String
Get
Number = _Number
End Get
Set(ByVal Value As String)
_Number = Value
End Set
End Property
Public Property Question() As String
Get
Question = _Question
End Get
Set(ByVal Value As String)
_Question = Value
End Set
End Property
Public Property Answer() As String
Get
Answer = _Answer
End Get
Set(ByVal Value As String)
_Answer = Value
End Set
End Property
End Class
The code for the form
Imports System.IO
Imports System.Xml.Serialization
Public Class Form1
Dim numQuestions() As String
Dim questions() As String
Dim answersGroup() As String
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Label1.Text = ""
Label2.Text = ""
Label3.Text = ""
Main()
End Sub
Private Sub Main()
Dim p As New clsQuestions
p.Number = "1,2,3,4,5,6,7,8,9,10"
p.Question = "Question 1,Question 2,Question 3," &
"Question 4,Question 5,Question 6,Question 7," &
"Question 8,Question 9,Question 10"
p.Answer = "Answer 1.1,Answer 1.2,Answer 1.3,Answer 1.4;" &
"Answer 2.1,Answer 2.2,Answer 2.3,Answer 2.4;" &
"Answer 3.1,Answer 3.2,Answer 3.3,Answer 3.4;" &
"Answer 4.1,Answer 4.2,Answer 4.3,Answer 4.4;" &
"Answer 5.1,Answer 5.2,Answer 5.3,Answer 5.4;" &
"Answer 6.1,Answer 6.2,Answer 6.3,Answer 6.4;" &
"Answer 7.1,Answer 7.2,Answer 7.3,Answer 7.4;" &
"Answer 8.1,Answer 8.2,Answer 8.3,Answer 8.4;" &
"Answer 9.1,Answer 9.2,Answer 9.3,Answer 9.4;" &
"Answer 10.1,Answer 10.2,Answer 10.3,Answer 10.4"
'Serialize object to a text file.
Dim objStreamWriter As New StreamWriter("C:\Users\Username\Documents\Questions.xml")
Dim x As New XmlSerializer(p.GetType)
x.Serialize(objStreamWriter, p)
objStreamWriter.Close()
'Deserialize text file to a new object.
Dim objStreamReader As New StreamReader("C:\Users\Username\Documents\Questions.xml")
Dim p2 As New clsQuestions
p2 = x.Deserialize(objStreamReader)
objStreamReader.Close()
numQuestions = p2.Number.Split(",")
questions = p2.Question.Split(",")
answersGroup = p2.Answer.Split(";")
End Sub
Private Sub btnNext_Click(sender As Object, e As EventArgs) Handles btnNext.Click
Static x As Integer
If x <= questions.Length - 1 Then
Label1.Text = ""
Label2.Text = ""
Label3.Text = ""
arrayIndex(x)
x += 1
End If
End Sub
Private Sub arrayIndex(ByVal num As Integer)
Label1.Text = numQuestions(num)
Label2.Text = questions(num)
Dim answers() As String
answers = answersGroup(num).Split(",")
For Each item As String In answers
Label3.Text &= item & Environment.NewLine
Next
End Sub
End Class

i have combo box i have to fill it with the database names.please help me

i have 3 text boxes and a combo box i have to give the server name,username and password in the text boxes and the combo box should display the database names.Please help me
Can we assume that, when you tagged this question with sql you actually mean that the database is SQL Server? If so then, to get a list of databases attached to an instance, create a SqlConnection with an appropriate connection string but no value for Initial Catalog. You can then call GetSchema on that connection and specify "Databases" as the collection. That will return a DataTable containing data about the databases. The names of the databases will be in the "database_name" column. Here's some code that I used for a dialogue where the user entered connection details like you're doing:
Public Class OptionsDialogue
Private populateServerList As Boolean = True
Private populateDatabaseList As Boolean = True
Private Sub OptionsDialogue_Load(ByVal sender As Object, _
ByVal e As EventArgs) Handles MyBase.Load
Me.LoadConnectionString()
'Me.LoadAppSettings()
End Sub
Private Sub serverCombo_DropDown(ByVal sender As Object, ByVal e As System.EventArgs) Handles serverCombo.DropDown
If Me.populateServerList Then
'Enumerate available SQL Server instances.
Dim serverTable As DataTable = SqlDataSourceEnumerator.Instance.GetDataSources()
Dim upperBound As Integer = serverTable.Rows.Count - 1
Dim serverNames(upperBound) As String
For index As Integer = 0 To upperBound
If serverTable.Rows(index).IsNull("InstanceName") Then
serverNames(index) = CStr(serverTable.Rows(index)("ServerName"))
Else
serverNames(index) = String.Format("{0}\{1}", _
serverTable.Rows(index)("ServerName"), _
serverTable.Rows(index)("InstanceName"))
End If
Next
Dim currentServerName As String = Me.serverCombo.Text
With Me.serverCombo
.BeginUpdate()
.Items.Clear()
.Items.AddRange(serverNames)
.SelectedItem = currentServerName
.Text = currentServerName
.EndUpdate()
End With
Me.populateServerList = False
End If
End Sub
Private Sub sqlServerSecurityOption_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles sqlServerSecurityOption.CheckedChanged
Dim sqlServerSecurity As Boolean = Me.sqlServerSecurityOption.Checked
Me.userLabel.Enabled = sqlServerSecurity
Me.userText.Enabled = sqlServerSecurity
Me.passwordLabel.Enabled = sqlServerSecurity
Me.passwordText.Enabled = sqlServerSecurity
End Sub
Private Sub databaseCombo_DropDown(ByVal sender As Object, ByVal e As System.EventArgs) Handles databaseCombo.DropDown
Using connection As New SqlConnection(Me.GetConnectionString(False))
Try
connection.Open()
'Enumerate available databases.
Me.databaseCombo.DataSource = connection.GetSchema("Databases")
Catch
MessageBox.Show("Unable to connect.", _
"Connection Error", _
MessageBoxButtons.OK, _
MessageBoxIcon.Error)
End Try
End Using
End Sub
Private Sub testButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles testButton.Click
If Me.TestConnection() Then
MessageBox.Show("Connection successful.", _
"Connection Successful", _
MessageBoxButtons.OK, _
MessageBoxIcon.Information)
Else
MessageBox.Show("Connection failed.", _
"Connection Failed", _
MessageBoxButtons.OK, _
MessageBoxIcon.Error)
End If
End Sub
Private Sub okButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles okButton.Click
If Me.TestConnection() OrElse _
MessageBox.Show("A connection could not be established using the specified settings." & _
Environment.NewLine & _
"Do you still want to save the connection settings?", _
"Connection Failed", _
MessageBoxButtons.OKCancel, _
MessageBoxIcon.Warning, _
MessageBoxDefaultButton.Button2) = Windows.Forms.DialogResult.OK Then
Dim configSaved As Boolean
configSaved = Me.SaveConnectionString
'configSaved = Me.SaveAppSettings
If configSaved OrElse _
MessageBox.Show("The connection settings could not be saved." & _
Environment.NewLine & _
"Do you still want to close the window?", _
"Save Failed", _
MessageBoxButtons.OKCancel, _
MessageBoxIcon.Error, _
MessageBoxDefaultButton.Button2) = Windows.Forms.DialogResult.OK Then
Me.DialogResult = Windows.Forms.DialogResult.OK
End If
End If
End Sub
Private Sub LoadConnectionString()
'Load the current connection string.
Dim builder As New SqlConnectionStringBuilder(My.Settings.PrimaryConnectionString)
'Display individual connection string properties.
Me.serverCombo.Text = builder.DataSource
Me.integratedSecurityOption.Checked = builder.IntegratedSecurity
Me.sqlServerSecurityOption.Checked = Not builder.IntegratedSecurity
Me.userText.Text = builder.UserID
Me.passwordText.Text = builder.Password
Me.databaseCombo.Text = builder.InitialCatalog
End Sub
Private Sub LoadAppSettings()
'Open the primary config file.
Dim config As System.Configuration.Configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
Dim appSettings As KeyValueConfigurationCollection = config.AppSettings.Settings
Dim osSecurity As Boolean
Boolean.TryParse(appSettings("OSSecurity").Value, osSecurity)
'Display individual connection string properties.
Me.serverCombo.Text = appSettings("ServerName").Value
Me.integratedSecurityOption.Checked = osSecurity
Me.sqlServerSecurityOption.Checked = Not osSecurity
Me.userText.Text = appSettings("UserName").Value
Me.passwordText.Text = appSettings("Password").Value
Me.databaseCombo.Text = appSettings("DatabaseName").Value
End Sub
Private Function GetConnectionString(ByVal includeDatabase As Boolean) As String
Dim builder As New SqlConnectionStringBuilder()
'Build a connection string from the user input.
builder.DataSource = Me.serverCombo.Text
builder.IntegratedSecurity = Me.integratedSecurityOption.Checked
builder.UserID = Me.userText.Text
builder.Password = Me.passwordText.Text
If includeDatabase Then
builder.InitialCatalog = Me.databaseCombo.Text
End If
Return builder.ConnectionString
End Function
Private Function TestConnection() As Boolean
Dim result As Boolean = False
Using connection As New SqlConnection(Me.GetConnectionString(True))
Try
connection.Open()
result = True
Catch
End Try
End Using
Return result
End Function
Private Function SaveConnectionString() As Boolean
Dim result As Boolean = False
'Open the primary config file.
Dim config As System.Configuration.Configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
For Each setting As ConnectionStringSettings In config.ConnectionStrings.ConnectionStrings
'Find the desired connection string.
If setting.Name.Contains("PrimaryConnectionString") Then
'Update the connection string from the user input.
setting.ConnectionString = Me.GetConnectionString(True)
'Save the changes to the config file.
config.Save(ConfigurationSaveMode.Modified)
ConfigurationManager.RefreshSection("connectionStrings")
'Force the connection string to reload the new value from the config file.
My.Settings.Reload()
result = True
Exit For
End If
Next setting
Return result
End Function
Private Function SaveAppSettings() As Boolean
Dim result As Boolean = False
'Open the primary config file.
Dim config As System.Configuration.Configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
Dim appSettings As KeyValueConfigurationCollection = config.AppSettings.Settings
appSettings("ServerName").Value = Me.serverCombo.Text
appSettings("DatabaseName").Value = Me.databaseCombo.Text
appSettings("OSSecurity").Value = Me.integratedSecurityOption.Checked.ToString()
appSettings("UserName").Value = Me.userText.Text
appSettings("Password").Value = Me.passwordText.Text
'Save the changes to the config file.
config.Save(ConfigurationSaveMode.Modified)
ConfigurationManager.RefreshSection("appSettings")
result = True
Return result
End Function
End Class

How can I end my loop?

I made a loop to show the balance when entered a name, but when I try to do it a second time. It doesn't return another output(messagebox). How can I end/restart the loop?
Public Class Form1
Dim intMax_Subscript As Integer = 7
Dim arrayNames(intMax_Subscript) As String
Dim arrayBalance(intMax_Subscript) As Double
Dim found As Boolean
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
CBO1.Items.Add("John One")
arrayNames(0) = CStr(CBO1.Items(0))
CBO1.Items.Add("Jack Two")
arrayNames(1) = CStr(CBO1.Items(1))
CBO1.Items.Add("John Three")
arrayNames(2) = CStr(CBO1.Items(2))
CBO1.Items.Add("Jack Four")
arrayNames(3) = CStr(CBO1.Items(3))
CBO1.Items.Add("John Five")
arrayNames(4) = CStr(CBO1.Items(4))
CBO1.Items.Add("Jack Six")
arrayNames(5) = CStr(CBO1.Items(5))
CBO1.Items.Add("John Seven")
arrayNames(6) = CStr(CBO1.Items(6))
CBO1.Items.Add("Jack Eight")
arrayNames(7) = CStr(CBO1.Items(7))
CBO2.Items.Add("235.50")
arrayBalance(0) = CDbl(CBO2.Items(0))
CBO2.Items.Add("78943.98")
arrayBalance(1) = CDbl(CBO2.Items(1))
CBO2.Items.Add("230781.10")
arrayBalance(2) = CDbl(CBO2.Items(2))
CBO2.Items.Add("78362.00")
arrayBalance(3) = CDbl(CBO2.Items(3))
CBO2.Items.Add("12097.20")
arrayBalance(4) = CDbl(CBO2.Items(4))
CBO2.Items.Add("89267.34")
arrayBalance(5) = CDbl(CBO2.Items(5))
CBO2.Items.Add("34959.06")
arrayBalance(6) = CDbl(CBO2.Items(6))
CBO2.Items.Add("559284.50")
arrayBalance(7) = CDbl(CBO2.Items(7))
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBalance.Click
Dim input As String = InputBox("Input a name")
Dim intcount As Integer = -1
Dim intSubscript As Integer = 0
Do While Not found And intcount < arrayNames.Length
If arrayNames(intSubscript) = input Then
found = True
MessageBox.Show("The balance of " & input & "'s is " & arrayBalance(intSubscript))
intSubscript = 0
intcount = -1
End If
intSubscript += 1
Loop
If Not arrayNames.Contains(input) Then
MessageBox.Show("Error: Name not found.")
End If
End Sub
You Need to reset the found to false after showing message box
If Not arrayNames.Contains(input) Then
MessageBox.Show("Error: Name not found.")
found = False
End If
you don't need the 'found' variable at all
Do While intcount < arrayNames.Length
If arrayNames(intSubscript) = input Then
MessageBox.Show("The balance of " & input & "'s is " & arrayBalance(intSubscript))
intSubscript = 0
Exit Do
End If
intSubscript += 1
Loop

Return false if char is repeated

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