I have a form with 3 text boxes, txt_customeracc, txt_customername, txt_customercontact
These 3 text boxes are optional and by default the text boxes will have "N/A" displaying on form load, but if a user enters information into one of them I want them to enter the information in the other two boxes also.
The code I am using is below
If txt_customername.Text <> "" Or txt_customername.Text <> "N/A" Or
txt_customercontact.Text <> "" Or txt_customercontact.Text <> "N/A" And
txt_customeracc.Text = "" Or txt_customeracc.Text = "N/A"
Then error1 += vbNewLine & "Please enter a correct Customer Account Number"
So from the above code I am expecting that if a user enters information in either the txt_customername or the txt_customercontact text boxes but not in the txt_customeracc box the warning should then appear but currently the warning message is displaying regardless of whether information is or isn't entered in any of the boxes. Can anyone tell me what I am doing wrong?
What is operator precedence ?
Your main problem here is that you have an issue with operator precedence. What is that ?
It is exactly the same issue as when doing calcuations, multiplication comes first, then comes addition. Well in VB .NET, And operator comes before Or, so what you have written in your code is evaluated as follow :
If txt_customername.Text <> "" Or
txt_customername.Text <> "N/A" Or
txt_customercontact.Text <> "" Or
(txt_customercontact.Text <> "N/A" And txt_customeracc.Text = "") Or
txt_customeracc.Text = "N/A"
Then
error1 += vbNewLine & "Please enter a correct Customer Account Number"
End If
Since this is not really what you want, let's build this together :
if customername OR customercontact is filled up
AND
customeracc is empty
That would give us :
if (
(txt_customername.Text <> "" Or txt_customername.Text <> "N/A") 'CustomerName is filled up
Or
(txt_customercontact.Text <> "" Or txt_customercontact.Text <> "N/A") 'Customer Contact is filled up
)
And
(txt_customeracc.Text = "" Or txt_customeracc.Text = "N/A") 'Customer account is empty
Then
'Do whatever
End If
Make it better, call a function
Another problem here is readability, this code may have errors because it's hard to read, so hard to debug.
What we can do is build a function that will check if a textbox is empty :
Private Function IsEmpty(Tb As Textbox) As Boolean
'Here we return true if tb.Text is empty or contains "N/A"
Return Tb.Text = "" Or Tb.Text = "N/A"
End Function
So that would make this a bit more readable :
if (Not IsEmpty(txt_customername) Or Not IsEmpty(txt_customercontact)) 'CustomerName or Customer Contact is filled up
And IsEmpty(txt_customeracc) 'Customer account is empty
Then
'Do whatever
End If
Make it better (2), Compare the strings
As stated by zaggler in his comment, here we don't use String Comparison. What if a user starts typing, then decides to put it back to N/A and writes it lowercase ("n/a") ? Well, we will make a mistake, believing that he did fill up the Textbox and you will end up searching for user "n/a" in your database, which is not a very good idea...
So let's compare the String, make our function even better :
Private Function IsEmpty(Tb As Textbox) As Boolean
'Here we return true if tb.Text is empty or contains "N/A" (or "n/a")
Return Tb.Text = "" Or (String.Compare(Tb.Text, "N/A", True) = 0)
End Function
Note
You can see here the advantage of functions. I wrote it because I didn't want to change to String.Compare() six times... Whenever you have the same code twice, it should be a function...
If you want to give the user a proper error message telling him what he has missed to fill out you have to split the if statement into several parts.
First check if all text boxes contain any valid data.
If not you can skip further checks directly.
If one textbox contains data check each and set error accordingly.
If (txt_customername.Text = "" OrElse txt_customername.Text = "N/A") AndAlso
(txt_customercontact.Text = "" OrElse txt_customercontact.Text = "N/A") AndAlso
(txt_customeracc.Text = "" OrElse txt_customeracc.Text = "N/A") Then
'No Error exit sub
Exit Sub
End If
'This part is only reached if one textbox contains data
If (txt_customername.Text = "" OrElse txt_customername.Text = "N/A") Then
error1 += vbNewLine & "Please enter a correct Customer Name"
End If
If (txt_customercontact.Text = "" OrElse txt_customercontact.Text = "N/A") Then
error1 += vbNewLine & "Please enter a correct Customer Contact"
End If
If (txt_customeracc.Text = "" OrElse txt_customeracc.Text = "N/A") Then
error1 += vbNewLine & "Please enter a correct Customer Account Number"
End If
As you can see I also recommend using short circuit OrElse and AndAlso which gives a littttttttle performance.
You could count the number of filled fields.
Dim numberFilled As Integer = 0
If txt_customername.Text <> "" And txt_customername.Text <> "N/A" Then
numberFilled += 1
End If
If txt_customercontact.Text <> "" And txt_customercontact.Text <> "N/A" Then
numberFilled += 1
End If
If txt_customeracc.Text <> "" And txt_customeracc.Text <> "N/A" Then
numberFilled += 1
End If
If numberFilled = 1 Or numberFilled = 2 Then
error1 += vbNewLine & "Please enter a correct Customer Account Number"
End If
Personally I would have a function IsValueEmpty that would check:
Function IsValueEmpty(ByVal value As String) As Boolean
If String.IsNullOrEmpty(value) Or value = "N/A" Then
Return True
End If
Return False
End Function
Could also Trim.
You could have the relevant message part stored in the Tag property of each textbox and use Linq :
Dim customerTextBoxes = {txt_customeracc, txt_customername, txt_customercontact}
Dim messages = Aggregate customerTextBox In customerTextBoxes
Where customerTextBox.Text = "" OrElse customerTextBox.Text = "N/A"
Select $"Please enter a correct {customerTextBox.Tag}")
Into ToArray
Then just check it's length against the initial one and if they're not equal aggregate the message for display
If customerTextBoxes.Length <> messages.Length Then error1 = String.Join(Environment.NewLine, messages)
Related
I have an access database, in many of the tables is a field called "Notes".
This field is used by techs to, well, make notes on the equipment.
But these notes need to be broken up into useful groups, as such we've chosen to use "|" as the delimiter. ( . , ; : - _ / \ all have valid notes uses and can not be assigned to this role)
I've tried :
If Split(rst!Notes, "|")(1).Property = "" Then
aNotesOver = ""
Else
aNotesOver = Split(rst!Notes, "|")(1)
End If
'AND:
If Split(rst!Notes, "|")(1) <> "" Then
aNotesOver = Split(rst!Notes, "|")(1)
Else
aNotesOver = Nz(Split(rst!Notes, "|"), "")
End If
'AND:
If Nz(Split(rst!Notes, "|")(1)) = "" Then
aNotesOver = ""
Else
aNotesOver = Split(rst!Notes, "|")(1)
End If
'AND I tried:
If Not IsNull(Split(rst!Notes, "|")(1)) Then
aNotesOver = Split(rst!Notes, "|")(1)
Else
aNotesOver = ""
End If
None of them work, and I keep getting the "Invalid use of Null " Error.
Anyone have any suggestions?
This is one of those unfortunate quirks of VBA. if the passed value is null, then the split function fails.
and if you pass a empty string, then the ubound() value of the array is -1!!!!
So, this is messy.
I would suggest that you build your own custom function:
Public Function MySplit(v As Variant, ix As Integer) As String
MySplit = ""
If IsNull(v) Then Exit Function
If v = "" Then Exit Function
Dim vBuf As Variant
vBuf = Split(v, "|")
If ix > UBound(vBuf) Then Exit Function
MySplit = vBuf(ix)
End Function
So you could add a delimter to this function.
But, now your code is:
aNotesOver = MySplit(rst!Notes, 1)
And if the 1 is larger then the number of values, it will still return ""
I'm pretty new to VBA and having issues with a Else statements running even when If conditions are met.
Pretty sure this is due to the If statement being within a For & Next
For iCnt = 1 To Len(Firstname)
If IsNumeric(Mid(Firstname, iCnt, 1)) Then
MsgBox "The Firstname cannot contain Numeric values"
ElseIf Len(Firstname) > 100 Then
MsgBox "The Firstname exceeds the character limit (100)"
Else
Sheet3.Cells(lRow, 2).Value = Me.Firstname.Value
End If
Next iCnt
Please any suggestions how to fix this?
Really you only want the first condition to exist in that FOR loop. The rest of it should be tested afterwards and only if that first condition never trips.
Consider instead:
Dim nameHasNumbers as boolean: nameHasNumbers = False
For iCnt = 1 To Len(Firstname)
If IsNumeric(Mid(Firstname, iCnt, 1)) Then
'number found toggle flag and exit the loop
nameHasNumbers = True
exit For
End If
Next iCnt
'Now alert the user or update the name cell
If nameHasNumbers Then
MsgBox "The Firstname cannot contain Numeric values"
ElseIf Len(Firstname) > 100 Then
MsgBox "The Firstname exceeds the character limit (100)"
Else
Sheet3.Cells(lRow, 2).Value = Me.Firstname.Value
End If
For each letter in the name you are going to get the Else to happen. Need to restructure the whole thing. I would put the checking into a function and then based on that result do your other work. If you need a message to inform the user of the reason for the name being invalid add that to the function. Your function can then do other testing on other conditions without affecting your calling code.
Private Function IsValidName(ByVal value As String) As Boolean
If Len(value) > 100 Then
IsValidName = False
Exit Function
Else
Dim charCounter As Long
For charCounter = 1 To Len(value)
If IsNumeric(Mid(value, charconter, 1)) Then
IsValidName = False
Exit Function
End If
Next
IsValidName = True
End If
End Function
When you want to check whether a string includes a digit, you can compare it to a Like pattern which matches a digit: FirstName Like "*[0-9]*"
That approach is simpler than looping through the string checking whether each character is a digit. And since it does not require the For loop, it should be easier to avoid the logic error in your code sample. (As long as the string length did not exceed 100 characters, it wrote a value to Sheet3.Cells(lRow, 2).Value again for each and every non-numeric character contained in FirstName.)
If FirstName Like "*[0-9]*" Then
MsgBox "The Firstname cannot contain Numeric values"
ElseIf Len(FirstName) > 100 Then
MsgBox "The Firstname exceeds the character limit (100)"
Else
Sheet3.Cells(lRow, 2).Value = Me.FirstName.Value
End If
I'm trying to send three string "huis" to crystal report parameter
he only work if i select one checkbox
i wanna crystal report give me what is selected on checkbox(huis)
select * from Mess22 where Cont in {?#huis}
Dim huis As String
If CheckBox1.Checked = True Then
huis = CheckBox1.Text
End If
If CheckBox2.Checked = True Then
If huis = "" Then
huis = CheckBox2.Text
Else
huis = huis & "," & CheckBox2.Text
End If
End If
Aver5.Load("Avert5.rpt")
Aver5.SetParameterValue("#huis", huis.ToString)
AvF.CR2.ReportSource = Aver5
AvF.ShowDialog()
Change the record selection formula to:
Cont in Split({?#huis}, ",")
This would turn the string into an array for comparison.
The other option is to design the parameter as a multi-value parameter and use the API to add the values one by one.
I have this if statement right here:
If lbl1.Text <> "Good" Or lbl2.Text <> "Good" Or lbl3.Text <> "Good" Then
MsgBox("Something.")
Exit Sub
End If
This works fine, but I also need to attach another condition to it, but for some reason I am drawing a blank on it. I need it to also pass that it is ok for lbl2 & lbl3 to be an empty string. In order words, if lbl1.text = "Good" then it is ok for lbl2 & lbl3 to be empty, therefore it will not exit sub.
If you look at it from the other way around, what you're saying is that if any one of the labels says "Good", then don't enter this statement, so, you could say enter this statement if that is not the case.
In other words:
If Not(lbl1.Text = "Good" Or lbl2.Text = "Good" Or lbl3.Text = "Good") Then
MessageBox.Show("Something.")
End If
Hope that does the trick!
What about a statement like this?
If Not ((lblA.Text = "Good" OrElse lblA.Text = String.Empty) AndAlso _
(lblB.Text = "Good" OrElse lblB.Text = String.Empty) AndAlso _
(lblC.Text = "Good" OrElse lblC.Text = String.Empty)) Then
MessageBox.Show("Something.")
End If
I'm trying to find a way to only allow a user to input ".32" or "Not Used" into my datagridviewcell. Right now my code stands as below. When I run the code all it does is change everything to "Not Used". Even if I type in ".32" it will change it to "Not Used". Is there anyway to fix this? I appreciate any help or suggestions anyone can give.
If (e.ColumnIndex = 6) Then ' This specifies the column number
Dim cellData = DataGridView1.Rows(e.RowIndex).Cells(e.ColumnIndex).Value.ToString
If cellData Is Nothing OrElse IsDBNull(cellData) OrElse cellData.ToString = String.Empty Then
MessageBox.Show("Cannot Be Empty") ' This will prevent blank datagridviewcells
DataGridView1.Rows(e.RowIndex).Cells(e.ColumnIndex).Value = "Not Used"
End If
Select Case cellData
Case 0.32
DataGridViewSize.Rows(e.RowIndex).Cells(e.ColumnIndex).Value = 0.32
Case Else
DataGridViewSize.Rows(e.RowIndex).Cells(e.ColumnIndex).Value = "Not Used"
End Select
End If
I think it no necessary to use select string
Better you change to Dim cellData = DataGridView1.Rows(e.RowIndex).Cells(e.ColumnIndex).Value