VB : Parentheses automatically added in error - vb.net

My colleagues frown upon me because according to our sourcesafe, I added parentheses to the method-property thus resulting in a stackoverflow.
Since I'm sure I did no such thing on purpose, I wonder if somehow I used a obscure shortcut which performed these changes.
This kind of stuff :
Public Function Opslaan() As Boolean
If something_wrong() Then
opslaan = False
End If
If opslaan = False Then
Do_Something_Else()
End If
Return opslaan
End Function
and this got changed into :
Public Function Opslaan() As Boolean
If something_wrong() Then
opslaan = False
End If
If opslaan() = False Then '' See the parentheses here added automatically
Do_Something_Else()
end If
Return opslaan
End Function
Any help is appreciated.

This looks like bad old VB6 code converted to VB.NET.
The problem is VB6 allowed you to treat the current function name as a variable and update its value all throughout the method. Then, when you exited the method whatever value this variable had would be returned to the caller. This syntax is confusing and should never be used, even in VB6 since there is a better way.
Update all code you find like this to something like:
Public Function Opslaan() As Boolean
Dim result As Boolean = True
If something_wrong() Then
result = False
end if
If result = False Then
Do_Something_Else()
End If
Return result
End Function
This is much clearer code and will never mistakenly call the same routine.
Also, this is totally personal preference, but I prefer to not check booleans with equals statements. So If result = False Then becomes If Not result Then and If result = true Then becomes If result Then. That almost always feels cleaner to me for Booleans.

Related

Looking for a better way to set properties for form controls

I'm using the code below in many forms and several applications:
Private Sub EnableEdit(strFieldname As String, Optional bUseRed As Boolean = False)
Me.Controls(strFieldname).Enabled = True
Me.Controls(strFieldname).Locked = False
If Not Me.Controls(strFieldname).ControlType = acCheckBox Then
Me.Controls(strFieldname).BackStyle = 1
If bUseRed Then
Me.Controls(strFieldname).ForeColor = vbRed
Else
Me.Controls(strFieldname).ForeColor = vbBlack
End If
End If
End Sub
' and the calls e.g.
EnableEdit ("arHerstellerArtikelNr")
EnableEdit ("arEAN")
EnableEdit ("arArtikelNrIxxtraNice")
EnableEdit ("arSort")
A recent change showed me, that it would be much better to have the code NOT duplicated in each Class Object. First my problem doing so was, that the code contains 'Me.Controls(strFieldname)' to address the properties I want to manipulate. For this reason it had to be in the Class Object itself --> requiring duplication.
So I rewrote my code. The design goal was: a way to call 'EnableEdit' from the events of several forms, but supplying the code for this not in the forms module itself, but in a module or class module that is supplied just once for the application. I think the way access works, I need to pass an additional parameter to distinguish the forms. However if the name of the form needs to be passed as an additional parameter (e.g. EnableEdit ("frmInventoryUpdate", "arSort")) the code is less readable and more error prone. So I came up with the idea to pass the name as an invariant: 'EnableEdit (Me.FormName, "arSort")'. This led me to the following solution:
Public Sub EnableEdit2(strFormName As String, strFieldname As String, Optional bUseRed As Boolean = False)
Dim frmCurrentForm As Form
Set frmCurrentForm = Forms(strFormName)
frmCurrentForm.Controls(strFieldname).Enabled = True
frmCurrentForm.Controls(strFieldname).Enabled = True
frmCurrentForm.Controls(strFieldname).Locked = False
If Not frmCurrentForm.Controls(strFieldname).ControlType = acCheckBox Then
frmCurrentForm.Controls(strFieldname).BackStyle = 1
If bUseRed Then
frmCurrentForm.Controls(strFieldname).ForeColor = vbRed
Else
frmCurrentForm.Controls(strFieldname).ForeColor = vbBlack
End If
End If
End Sub
' and the calls e.g.
Call EnableEdit2(Me.FormName, "arHerstellerArtikelNr")
Call EnableEdit2(Me.FormName, "arEAN")
Call EnableEdit2(Me.FormName, "arArtikelNrIxxtraNice")
Call EnableEdit2(Me.FormName, "arSort")
The solution is acceptable for me, however I wonder if there is any way to suppress even the 'Me.FormName' in the call and thus making the calls nicer?
Never pass the form name, always pass the form:
Public Sub EnableEdit2(frmCurrentForm As Form, strFieldname As String, Optional bUseRed As Boolean = False)
frmCurrentForm.Controls(strFieldname).Enabled = True
frmCurrentForm.Controls(strFieldname).Enabled = True
frmCurrentForm.Controls(strFieldname).Locked = False
If Not frmCurrentForm.Controls(strFieldname).ControlType = acCheckBox Then
frmCurrentForm.Controls(strFieldname).BackStyle = 1
If bUseRed Then
frmCurrentForm.Controls(strFieldname).ForeColor = vbRed
Else
frmCurrentForm.Controls(strFieldname).ForeColor = vbBlack
End If
End If
End Sub
'Call it:
EnableEdit2 Me, "arHerstellerArtikelNr"
'Never use Call, that's a relic of very old code and not needed in modern code
Passing the form name causes additional overhead, goes wrong when your form is a subform, and goes wrong when you want to allow multiple instances of the same form (that all have the same name of course).
You always want to pass the form directly, both because it avoids these problems and because it's more concise.
For a more thorough rework, I'd avoid passing the field name, and would use the tag property instead to determine which fields need this enabling/disabling, given that fields don't need to be disabled or enabled independently.

I am using a method with a stored procedure, but it's always returning false

I am using bool method with Visual Studio 2015 and SQL Server 2005.
When I am passing correct details and click loginButton, the code always returns false from the stored procedure.
This is my stored procedure in SQL Server 2005:
ALTER PROCEDURE [dbo].[UserCheckLoginDetails]
(#IsLoginIdCorrect BIT OUTPUT,
#IsPasswordCorrect BIT OUTPUT,
#LoginID NVARCHAR(200),
#Password NVARCHAR(20)
)
AS
BEGIN
SET #IsLoginIdCorrect = 0
SET #IsPasswordCorrect = 0
IF EXISTS (SELECT * FROM UserInfo
WHERE loginid = #LoginID AND password = #Password)
BEGIN
SET #IsLoginIdCorrect = 1
SET #IsPasswordCorrect = 1
END
ELSE
IF EXISTS (SELECT * FROM UserInfo WHERE loginid = #LoginID)
BEGIN
SET #IsLoginIdCorrect = 1
END
END
This is my method returning True or False:
Private Sub GetIsUserLoginCorrect(IsLoginIdCorrect As Boolean, IsPasswordCorrect As Boolean)
Using Conn As New SqlConnection(_SqlCon)
Using cmd As New SqlCommand("UserCheckLoginDetails", Conn)
cmd.CommandType = CommandType.StoredProcedure
Conn.Open()
'OutPut Parameters
cmd.Parameters.Add("#IsLoginIdCorrect", SqlDbType.Bit).Direction = ParameterDirection.Output
cmd.Parameters.Add("#IsPasswordCorrect", SqlDbType.Bit).Direction = ParameterDirection.Output
'InPut Parameters
cmd.Parameters.AddWithValue("#LoginID", LoginIDTextBox.Text)
cmd.Parameters.AddWithValue("#Password", PasswordTextBox.Text)
cmd.ExecuteNonQuery()
' Assign Parameters
IsLoginIdCorrect = Convert.ToBoolean(cmd.Parameters("#IsLoginIdCorrect").Value)
IsPasswordCorrect = Convert.ToBoolean(cmd.Parameters("#IsPasswordCorrect").Value)
End Using
End Using
End Sub
This is the Login button click event handler, even when I provide the correct values, it still always returns false:
Private Sub LoginButton_Click(sender As Object, e As EventArgs) Handles LoginButton.Click
Try
Dim IsLoginIdCorrect, IsPasswordCorrect As Boolean
GetIsUserLoginCorrect(IsLoginIdCorrect, IsPasswordCorrect)
If IsLoginIdCorrect And IsPasswordCorrect = True Then
Me.Hide()
' User Information
DeshBoard.MainUserIdLabel.Text = Me.MainUserIdLabel.Text
DeshBoard.UserNameLabel.Text = Me.UserNameLabel.Text
DeshBoard.UserLoginIdLabel.Text = Me.UserLoginIdLabel.Text
DeshBoard.UserLevelLabel.Text = Me.UserLevelLabel.Text
'Organanization Information
DeshBoard.MainOrgIDLabel.Text = Me.MainOrgIDLabel.Text
DeshBoard.OrgNameLabel.Text = Me.OrgNameLabel.Text
DeshBoard.OrgTelLabel.Text = Me.OrgTelLabel.Text
DeshBoard.OrgEmailLabel.Text = Me.OrgEmailLabel.Text
DeshBoard.OrgAddressLabel.Text = Me.OrgAddressLabel.Text
DeshBoard.Show()
Else
If IsLoginIdCorrect = False Then
MessageBox.Show("Login ID is not correct...!!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
LoginIDTextBox.Clear()
PasswordTextBox.Clear()
LoginIDTextBox.Focus()
Else
MessageBox.Show("Password ID is not correct...!!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
PasswordTextBox.Clear()
PasswordTextBox.Focus()
End If
End If
Catch ex As ApplicationException
MessageBox.Show("Error: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
Thank you very much.
You need to add ByRef to both arguments in Sub GetIsUserLoginCorrect().
To demonstrate, try the following with and without ByRef.
Private Sub ChangeBoolean(ByRef TorF As Boolean)
TorF = True
End Sub
Private Sub OPCode2()
Dim TorF As Boolean
ChangeBoolean(TorF)
Debug.Print(TorF.ToString) ' Result False without ByRef in ChangeBoolean
'When ByRef is added result is True
End Sub
First off, a method can refer to either a sub or a function. A sub is a method that performs an action. A function is a method that calculates or retrieves one or more values.
A sub should not be called Getxxx, because its primary purpose should not be returning a value.
A function should be used to return values. Since you are trying to retrieve multiple values, if you were using 2017 I would suggest returning a named tuple with your two values, since you aren’t I would create an object that has the values and return that.
On a totally different note, you really can’t tell the difference between right user wrong password and wrong user right password and wrong user wrong password - so you shouldn’t tell someone you can. You just say login unsuccessful login, or invalid username/password combination.
There's a lot wrong with your code.
Firstly, why are you using so much of SQL code ? Correct me if i am wrong : You are trying to build a log in system. So much of SQL code or even the stored procedure is worthless here. You can simply write the SQL statements in your code by using the SqlCommand class. Even though you are using the ALTER PROCEDURE statement, i can surely say that things can be simplified here.
You are also using the Me keyword. It's not C# where the use of this(same as Me in VB.Net) becomes compulsory. I assume it's a Windows Forms Application and if that's so, then using Me keyword to access it's child elements wouldn't result in any different if it's not used at all.
The next worth mentioning issues is your Name Conventions. Most or should i say all of your variables have the same name. For example : IsLoginIdCorrect - used both as a parameter of a method and also a variable inside a method.
The next issues is in these two lies :
Dim IsLoginIdCorrect, IsPasswordCorrect As Boolean
GetIsUserLoginCorrect(IsLoginIdCorrect, IsPasswordCorrect)
You are passing the boolean variables before they have been assigned any value. You are lucky it's not C# or this wouldn't even compile. Passing the boolean variables without assigning any value will, by default, set their values to False. So, literally, you are always passing the same value in which case, the outcome will always be the same.
The next issue is in your If statement inside your LoginButton_Click method aka LoginButton's click event handler's method :
If IsLoginIdCorrect And IsPasswordCorrect = True Then
The if statements, if described in simple words, means : If IsLoginIdCorrect and IsPasswordCorrect are true, then proceed.... So, in this case, IsPasswordCorrect = True doesn't affect much. However, this is not the best practice too. You should better follow the following coding rule while using If statements:
If (IsLoginIdCorrect = True AndAlso IsPasswordCorrect = True) Then
AndAlso operators evaluates each side just like the And operator. The difference is that it would return False if the left side(IsLoginIdCorrect, in this case) returns False.
The next issues is the usage of ApplicationException. I don't understand why, in this era, you are using that class! This class is usually used to derive from and create exceptions. You can simply use Exception instead of ApplicationException.
Your Try-Catch block seems not useful as well. All of your codes inside the LoginButton_Click are in If conditions and they perform very basic operation. It is unlikely to ever throw any exception at all.
Your logics, for most part, are illogical(sorry to put it this way). In your GetIsUserLoginCorrect method, you are setting IsLoginIdCorrect and IsPasswordCorrect to either true or false but it wouldn't matter because they are parameters of the method itself. So even if you set their values, they will be reset when you call the method again. The reason why ByRef (according to Mary's answer) works is because ByRef, in short, means that you are pointing to original variable that you passed(not it's copy).
And finally, the solution you are looking for....
Even though i see you have marked Mary's answer as the answer, i would like to help you out a bit as-well.
Firstly, get rid of the stored procedure if possible and also if you are not using it anywhere else. I see you are using the If Exist condition inside your SQL queries. This is actually a nice move because according to performance reports, checking if data exists in a database/table using IF EXISTS yields the fastest output. So bravo for that one. But if you follow my advice and want to ditch the stored procedure, then you need to get rid of the IF EXISTS statement as well. Rather, you can simply use the SELECT statement itself, use the ExecuteScalar method of the SqlCommand class, convert it's value to Integer and check if the value of the Integer is 1 or not.
Example :
Dim cmd = New SqlCommand("SELECT COUNT(*) FROM UserInfo
WHERE loginid = #LoginID AND password = #Password")
Dim Exists = Convert.ToInt32(cmd.ExecuteScalar)
If Exists = 1 Then
''Code if data exists
End if
Note that i have used Convert.ToInt32 here. This will prevent null-reference exception as when ExecuteScalar returns Null, it will be converted to 0 integer value.
Also, why are you using GetIsUserLoginCorrect as method ? You can simply use it as a function and return required values. As you are returning multiple values, you can easily use the Tuple type as your function's type:
Private Function GetIsUserLoginCorrect(IsLoginIdCorrect As Boolean, IsPasswordCorrect As Boolean) As Tuple(of Boolean, Boolean)
....
....
return Tuple.Create(IsLoginIdCorrect, IsPasswordCorrect)
End Sub
Usage
Dim IsLoginCorrect = GetIsUserLoginCorrect(first_boolean_variable,second_boolean_variable).Item1
Dim IsPasswordCorrect = GetIsUserLoginCorrect(first_boolean_variable,second_boolean_variable).Item2
One last thing. As you are showing DeshBoard form after hiding the main form, make sure to call MainForm.Close on the Dashboard form's Closing/Closed event. This will ensure the application's exit(unless you have other plans for the main form, of course).
Hope this answer helps you.

Passing & changing control parameters (.Visible, .Text, etc) within a function

I have a validation I run on multiple inputs on a page (checking valid dates on each date-entry textbox, for example). I want to have a single function to pass the information into, instead of duplicating the same code across the whole page.
Right now, I have this:
Private Function HasDateError(ByRef dateErrorDiv As HtmlGenericControl, txtDate As TextBox) As Boolean
dateErrorDiv.Visible = False
If (date is not valid)
dateErrorDiv.Visible = True
Else
txtDate.Text = Date.Parse(txtDate.Text)
' I know this seems silly, but it fixes problems where users enter a date in a weird format and don't know why it was wrong
End If
Return dateErrorDiv.Visible
End Function
The problem I'm having:
Despite passing ByRef, dateErrorDiv.Visible and txtDate.Text aren't being updated by this code.
How do I pass controls (HtmlGenericControl, TextBox, etc) so I can update their properties (.Visible, .Text, etc) from within a function?
Edit: I have tried passing both as ByVal and ByRef, and I used a breakpoint to verify that the line dateErrorDiv.Visible = True is being hit, and that the value isn't changing.
As a test, I even simplified the function to the following (and again used breakpoints to verify that the value of .Visible never changed):
Private Function HasDateError(ByRef dateErrorDiv As HtmlGenericControl, txtDate As TextBox) As Boolean
dateErrorDiv.Visible = False
dateErrorDiv.Visible = True
Return dateErrorDiv.Visible
End Function

VBA - Passing variable between modules

I'm new to VB6, and trying to write some macro in use for CorelDraw.
I have a variable that need to be passed from Class module to Standard module, in my Class Module "SaveOptClass" I have a public variable called IsSaved and it's set on the class module:
Public IsSaved As Boolean
Public Sub SaveFile()
If <some triggers> Then
IsSaved = True
End If
In Standard module:
Sub DoSave()
Dim SaveClass As SaveOptClass
Set SaveClass = New SaveOptClass
If SaveClass.IsSaved = True Then
ActiveDocument.Save
Else
Form1.Show
End If
End Sub
Basically I'm trying to pass "IsSaved" boolean value from class module to standard. (If IsSaved is true, save the document or else display a form.)
I have tested that the boolean is True when I executed the code, but I can't get the state to pass to the other module.
Is there something I miss here? Thanks in advance.
As already answered by #shahkalpesh the problem is that you're not using a meaningful instance of SaveOptClass.
In my opinion the best way to design this kind of dependency is by mean of a parameter in the routine is using it and avoid as much as possible the use of global variables.
In your case this brings to this rewriting:
' in someOtherModule
Public Sub DoSave(saveOptObj as SaveOptClass)
If saveOptObj.IsSaved Then ' = True is unnecessary
ActiveDocument.Save
Else
Form1.Show
End If
End Sub
The client code could be:
private saveOptObj as SaveOptClass
Public Sub SaveFile()
If <some triggers> Then
saveOptObj.IsSaved = True
End If
' ....
someOtherModule.DoSave(saveOptObj)
' ...
Consider also, at this point, a renaming of DoSave, given that the actions taken suggest different semantics. In similar cases is preferable moving the If Else logic in the caller. Anyway, if you prefer to group actions with different semantics in the same routine you'd better use namings like DoSaveOr<SomethingElse>.

VB.NET: short cuts in code

Why is the following VB.NET code setting str to Nothing in my VS2005 IDE:
If Trim(str = New StreamReader(OpenFile).ReadToEnd) <> "" Then
Button2.Enabled = True
TextBox1.Text = fname
End If
OpenFile is a Function that returns a FileStream
EDIT: If the above line containing Trim is not correct, is there a way to achieve the intended result in only one line?
The code is never setting str at all:
If Trim(str = New StreamReader(OpenFile).ReadToEnd) <> "" Then
This line doesn’t set str, it compares it to the result of reading the file.
In VB, the = operator has two meanings, depending on context. If used in a statement, it assigns the right-hand expression to the left-hand expression. If used in any other context (i.e. in an expression), it performs an equality comparison, not an assignment.
Thus, in VB you must write the following:
str = New StreamReader(OpenFile()).ReadToEnd()
If str.Trim() <> "" Then …
Notice that I’ve replaced the free function Trim by a method call to make the code more consistent with common .NET coding practices.
The first thing to do when starting any VB.Net project is to make sure that Option Explicit and Option Strict are both set to true in the project settings. Only ever disable either of them if you have a specific reason (you need late binding or are taking over some old horrible code).
This would have stopped that code from even compiling and would have shown you the error right away.
Because you're not setting str, you're comparing it, then trimming the result of the comparison (basically trimming either "True" or "False"
If Trim(str = New StreamReader(OpenFile).ReadToEnd) <> "" Then
This doesn't actually set str, this breaks down to the following code
Dim str as string ' Defaults to nothing/""
Dim boolValue as bool = (str = New StreamReader(OpenFile).ReadToEnd)
If Trim(boolValue) <> "" Then
' This is always true, as "True" and "False" will never = ""'
...
End If