VB.net Logic Error - vb.net

This is supposed to be a program that tells how long it would take you to download a given size of file after the user inputs their download speed. intOne doesn't seem to be affected at all by the function that I have created to determine what intOne's value should be. I'm reasonably sure that the equation I'm using is correct.
Public Class Form1
Private tSize As System.Drawing.Size
Private checkUserSpeed As Long = 0
Private checkBitByte As Integer = 0
Private setSize As Integer = 0
Private checkUserSize As String = ""
Private Answer As Double = 0
Private ReadOnly Property checkDwnldSize() As String
Get
Return ComboBox1.Text
End Get
End Property
Function checkDownloadSize(ByVal checkUserSize As String)
Dim suffixes As New List(Of String)({"b", "k", "m", "g", "t", "p", "e", "z"})
Dim index As Long = suffixes.IndexOf(checkUserSize.Substring(0, 1).ToLower) > -1
If index > -1 Then
Return checkUserSpeed / 1024 ^ index
Else
Return False
End If
End Function
Function checkForByte(ByVal checkUserSize)
If Microsoft.VisualBasic.Right(checkUserSize.ToLower, 7) = "byte(s)" Then
checkBitByte = 1
checkDownloadSize(checkUserSize)
Return True
End
Else
Return False
End If
Return checkBitByte
Return checkUserSpeed
End Function
Function checkForBit(ByVal checkUserSize)
If Microsoft.VisualBasic.Right(checkUserSize.ToLower, 6) = "bit(s)" Then
checkBitByte = 8
checkDownloadSize(checkUserSize)
Return True
End
Else
checkForByte(checkUserSize)
Return False
End If
Return checkBitByte
Return checkUserSpeed
End Function
Function Calculate(ByVal checkUserSpeed, ByVal checkUserSize)
checkForBit(checkUserSize)
Return Answer
End Function
Private Sub FitContents()
tSize = TextRenderer.MeasureText(TextBox3.Text, TextBox3.Font)
TextBox3.Width = tSize.Width + 10
TextBox3.Height = tSize.Height
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Calculate(Convert.ToInt32(TextBox3.Text), ComboBox3.Text)
Answer = checkBitByte * ((1024 ^ setSize) / checkUserSpeed)
TextBox1.Text = Answer
End Sub
Private Sub TextBox3_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox3.TextChanged
Call FitContents()
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Form2.Show()
End Sub
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Form3.Show()
End Sub
End Class
Help would be greatly appreciated.

You never assign any value to intOne, so it starts with value 0. So this:
intOne = intOne / 1024 ^ 3
is the same as this:
intOne = 0 / 1024 ^ 3
which is of course this:
intOne = 0
As an aside:
Don't use Dim at the class/form level, use Private.
Always use As <ReturnType> when decalring you functions
Turn on Option Strict in your language settings.
Dim intTwo As Integer = Nothing doesn't do anything useful. Use
Dim intTwo As Integer = 0 instead.
Always declare your variables as a type as well (Dim tSize is missing its type)
Followup to your edits:
This:
Function checkForByte(ByVal checkUserSize)
Should be this:
Function checkForByte(ByVal checkUserSize As Long)
Fix this in all places in your code. Everything should have an As DataType. If you turned on Option Explict and Option Strict like was suggested the compiler will locate these problems for you.
Next, do not name local variables and/or parameters the same as your class/form level private variables. I personally prefix my instance variables like this:
Private _checkUserSpeed As Long = 0
Note the underscore. Some people use a lowercase m instead:
Private mCheckUserSpeed As Long = 0
Pick something and be consistent. This makes it clear the scope of a variable.
Also this code is bad, the second Return will never be hit:
Return checkBitByte
Return checkUserSpeed
Finally, assuming you are trying to populate the variable _checkUserSpeed with a value, you are still not ever doing it. Search your code and look for any place you are doing this:
_checkUserSpeed = something
You won't find it. So that variable will always be 0.
None of these are really VB.NET specific issues. All of these best-practices would apply equally to C# or any other langue.

You should look into cleaning up your code first, to improve readability. Avoid code repetition at all costs. If you think you cannot do otherwise, lean towards data repetition instead, i.e. create an XML file to store your values, but keep the code clean. Any errors you find later will then stand out like white crows.
For example, something like this:
Function checkDownloadSize(ByVal strOne As String)
Dim suffixes As New List(Of String)({"b", "k", "m", "g", "t", "p", "e", "z"})
Dim index As Long = suffixes.IndexOf(strOne.Substring(0, 1).ToLower) > -1
If index > -1 Then
Return intOne / 1024 ^ index
Else
Return False
End If
End Function
roughly replaces your two pages of checkDownloadSize and checkSize.
Notice how every function here is called only once. If you later decide to swap ToLower with your custom implementation, it needs to be done only once. Not only a performance improvement, it also makes your code more maintainable in the long run.
Another point is that I am not using Microsoft.VisualBasic namespace in the above code, and switched to Substring instead. This will ease your burden with migration to C#, and also make native C# devs understand your code better.

Related

Confused As To Why This Function Does Not Call?

I'm trying to call this function into a procedure and am confused on why this is not working, I've looked up how to format a function call and don't understand my mistakes.
Structure Stock
Dim category As String
Dim price As Integer
Dim size As String
Dim sku As String
Dim color As String
End Structure
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim stockArray() As String =
IO.File.ReadAllLines("stockInventory.txt")
End Sub
Private Sub btnNewSave_Click(sender As Object, e As EventArgs) Handles btnNewSave.Click
Dim answer
answer = check(sku, stockArray)
End Sub
Function check(sku, stockArray) As Boolean
Dim flag As Boolean
Dim numVar = -1
numVar = Array.IndexOf(stockArray, txtSKU.Text)
If numVar = -1 Then
flag = False
End If
If numVar <> -1 Then
flag = True
End If
Return flag
End Function
It gives me an error saying,
sku is not declared. It may be inaccessible due to its protection
level
I have a structure where sku is defined as being a string. Do I have to declare it again in this sub for it to work?
You can fine-tune this code a bit:
Function check(ByVal stockArray as String()) As Boolean
Return Array.IndexOf(stockArray, txtSKU.Text) >= 0
End Function
It'll return if the element is in the Array.
If your file is very very large and you are doing many searches, I recommend storing in a HashSet instead of an array to get O(1) searching, instead of the O(n) you are getting.
I notice your stock array, has to be declared at the class level, not the method level, to be accessible by other methods.

How to use Function return

I'm wondering if this is the right way to do this.
I have this sample code that should represent a user action, and a calculation done in a function, this function should then return the value to my sub?
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim i As Integer = 1
Test_function(i)
MsgBox(i)
End Sub
Private Function Test_function(ByVal i As Integer)
i = i + 1
Return (i)
End Function
When i run this piece of code I get:
i = 1 in sub
i = 2 in function
i = 1 in sub?
How do you get the i = 2 into my sub? Or is this not the correct way of using this?
I think what you're asking is why does i not get changed by the call to Test_function.
Let's break down your code.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim i As Integer = 1 'creating a variable named i, value 1.
Test_function(i) 'passing the value of the variable i to test function, but not doing anything with what the function returns.
MsgBox(i) 'calling messagebox with the value i.
End Sub
Private Function Test_function(ByVal i As Integer) 'creating a new variable also named i with the value being passed in.
i = i + 1 'incrementing the value of the i variable by 1.
Return (i) 'returning i
End Function
So there are a few concepts that you're misunderstanding as far as I can tell- what ByVal means, perhaps the concept of variable scoping, as well as what Return does.
The obvious answer is that you're not using the value returned by Test_function. If you had i = test_Function(i), then i would be incremented by the call to Test_function
Another approach would be to pass i ByRef instead of ByVal- if you did that, the i in the scope of your Test_function method would be the same as the i in the scope of your Button1_Click method. But because you are passing it ByVal, the i variables are actually two completely different variables.
There is nothing to wonder, it's only a simple misunderstanding. you are printing the actual value of i if you Call like this:
MsgBox(Test_function(i))
Then both will be the same;
or you can check this in following way:
Dim tempVal = Test_function(i)'<-- will give 2
MsgBox(i)'<--- will give 1
this is because you are passing the value of i not i as reference, if you pass it as reference then also both will be the same.
So if you change the function signature as follows:
Private Function Test_function(ByRef i As Integer)
i = i + 1
Return (i)
End Function
same function call will give you both values as 2
Dim tempVal = Test_function(i)'<-- will give 2
MsgBox(i)'<--- will give 2
Reference ByVal and ByRef

the function does not seem to change value when called upon 3 times

I am writing code in visual basic. the goal of the program is to get a function to randomly pick a string from a array when called upon. the problem is it is not choosing a different value when the button calls it to do so. I have no idea why it is doing this.
Also anyone know how to get multlines to print in a label or text? here is my code.
Public Class lbl
Public Function Noun() As String
Dim rand As New Random
Dim index As Integer
Dim nouns() As String = {"boy", "girl", "dog", "town", "car"}
Dim sentence As String ' used to build a sentence
index = rand.Next(5)
sentence = nouns(index)
Return sentence
End Function
Public Function outs(ByVal n1 As String) As String
Dim result = n1
Return result
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
lblRandom.Text = outs(Noun()) & outs(Noun())
lblRandom1.Text = outs(Noun())
End Sub
Public Shared Function RandomNumber(ByVal lowerBound As Integer, ByVal upperBound As Integer) As Integer
Return CInt(Math.Floor((upperBound - lowerBound + 1) * Rnd())) + lowerBound
End Function
Public Function Noun() As String
Dim rand As New Random
Dim index As Integer = -1
Dim nouns() As String = {"boy", "girl", "dog", "town", "car"}
Dim sentence As String ' used to build a sentence
index = RandomNumber(0, 4)
sentence = nouns(index)
Return sentence
End Function
Public Function outs(ByVal n1 As String) As String
Dim result = n1
Return result
End Function
Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
lblRandom.Text = outs(Noun()) & outs(Noun())
lblRandom1.Text = outs(Noun())
End Sub
The problem is that you re-create a new random generator each time the Noun() function is called. The random number generator should be a global variable.
The problem is that the .NET random number generator generates random numbers based on a seed. The seed is an integer based on the current system date and time. If you call the random number generator a number of times in quick succession, the same seed is likely to be used and the same "random" number will be generated. The solution is to declare the Random object outside of the procedure in which you wish to generate the random number and to pass a seed to its constructor which is built from the current (random) date and time.
To answer your other questions. Label controls will automatically wrap text if the text contains carriage returns. I have added a carriage return below for lblRandom.
To wrap text in a text box, set its Multiline property to True.
The code that #Aly El-Haddad posted will also work but it contains some VB6 legacy code. I have tried to keep it as .NET as possible. I have also eliminated the superfluous "outs" procedure and made it flexible so that you can add or delete elements in the "nouns" array. Note that with the line "index = rand.Next(5)", you are including element 5 of the array which doesn't exist. The upper bound of the zero-based array is 4 so an "Index was outside the bounds of the array" error will be thrown when your random number generator returns 5.
Private myRandom As New Random(CType(DateTime.Now.Ticks Mod Int32.MaxValue, Integer))
Private Function Noun() As String
Dim index As Integer
Dim nouns() As String = {"boy", "girl", "dog", "town", "car"}
index = myRandom.Next(nouns.GetLowerBound(0), nouns.GetUpperBound(0))
Return nouns(index)
End Function
Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
lblRandom.Text = Noun() & Constants.vbNewLine & Noun()
lblRandom1.Text = Noun()
End Sub

Search from a list of string() in VB.NET

I am trying to find if mylines() contains a value or not. I can get the value by mylines.Contains method:
Dim mylines() As String = IO.File.ReadAllLines(mypath)
If mylines.Contains("food") Then
MsgBox("Value Exist")
End If
But the problem is that I want to check if mylines() contains a line which starts with my value. I can get this value from a single line by mylines(0).StartsWith method. But how do I find a string from all the lines which is starting from some value, e.g. "mysearch" and then get that line number?
I am using a for loop to do so, but it is slow.
For Each line In mylines
If line.StartsWith("food") Then MsgBox(line)
Next
Constrained to code for .NET 2.0, please.
Here's one way with Framework 2.0 code, simply set SearchString with the the string you want to search for:
Imports System.IO
Public Class Form1
Dim SearchString As String = ""
Dim Test() As String = File.ReadAllLines("Test.txt")
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
SearchString = "Food"
End Sub
Private Function StartsWith(s As String) As Boolean
Return s.StartsWith(SearchString)
End Function
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim SubTest() As String = Array.FindAll(Test, AddressOf StartsWith)
ListBox1.Items.AddRange(SubTest)
End Sub
End Class
When I test this with a file with 87,000 lines, it takes about .5 sec, to fill the listbox.
I'm not a VB guy, but I think you could use Linq:
Dim mylines() As String = IO.File.ReadAllLines(mypath)
??? = mylines.Where(Function(s) s.StartWith("food")) //not sure of the return type
Check out: How do I append a 'where' clause using VB.NET and LINQ?

How do i get the object from one sub to the other sub

What i am trying to do is to get the intGuestID1 from page_load to be used in bth_add area
Because i am trying to get the ID when it has been clicked from another form to frmAddFollowUp so i tried to request it from the page_load as when i request from the add button, it only gives me the number 0 instead of the id from the previous form.
Partial Class frmAddFollowUp
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim objCDBFeedback As New CDBFeedback
Dim objCDBDepartment As New CDBDepartment
Dim intGuestID1 As Integer
Dim arrList As New ArrayList
If Page.IsPostBack = False Then
intGuestID1 = Request.QueryString("id")
arrList = objCDBDepartment.getAllDepartmentDropDownList
lstDepartment.DataSource = arrList
lstDepartment.DataTextField = "DepartmentName"
lstDepartment.DataValueField = "Department"
lstDepartment.DataBind()
End If
End Sub
Protected Sub btnAdd_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAdd.Click
Dim CheckBoolean As Boolean = True
Dim objCDBFeedback As New CDBFeedback
Dim objCFeedback As New CFeedback
If txtStaffName.Text = "" Then
lblValidateStaffName.Text = "*Please enter Staff Name."
CheckBoolean = False
Else
lblValidateStaffName.Text = ""
End If
If txtFollowUpSummary.Text = "" Then
lblValidateFollowUpSummary.Text = "*Please enter Follow up summary."
CheckBoolean = False
ElseIf txtFollowUpSummary.Text.Contains("'") Then
txtFollowUpSummary.Text = txtFollowUpSummary.Text.Replace("'", "''")
Else
lblValidateFollowUpSummary.Text = ""
End If
If txtAmount2.Text = "" Then
lblValidateAmount2.Text = "*Please enter the Amount or put in NIL if there is no amount."
CheckBoolean = False
Else
lblValidateAmount2.Text = ""
End If
If CheckBoolean = False Then
If txtStaffName.Text.Contains("''") Then
txtStaffName.Text = txtStaffName.Text.Replace("''", "'")
End If
If txtFollowUpSummary.Text.Contains("''") Then
txtFollowUpSummary.Text = txtFollowUpSummary.Text.Replace("''", "'")
End If
Else
Dim intNumOfRecordsAffected As Integer
objCFeedback.GuestId = intGuestID1
objCFeedback.Feedback = txtFollowUpSummary.Text
objCFeedback.Department = lstDepartment.SelectedItem.Value
objCFeedback.StaffName = txtStaffName.Text
objCFeedback.Amount = txtAmount2.Text
intNumOfRecordsAffected = objCDBFeedback.addNewFollowUp(objCFeedback)
Response.Redirect("frmIncident.aspx")
End If
End Sub
You may either specify ByRef parameter type or use Function that returns reference of an object. In your code-snippet, you may declare variable at class-level (fields) so you may use them in different event handlers/sub.
Make intGuestID1 a private member variable. That will allow you to access this variable in both functions.
Is this code compiling? I do not see intGuestID1 being declared in btnAdd_Click, this should be throwing an error.
To declare a private member variable add the following above the Page_Load function, for example:
Partial Class frmAddFollowUp
Inherits System.Web.UI.Page
Private _intGuestID1 as Integer ' The _ prefix is just a naming convention that is used for class member variables, if you don't like it, you can remove it.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Now, in your Page_Load method, remove the line Dim intGuestID1 As Integer, as you no longer need to declare this. Finally, anywhere you see intGuestID1, rename it to _intGuestID1
Also, some ways to possibly refactor this is to create a Read Only Property that encapsulates the fact that you're getting _intGuestID1 from the QueryString. See the following example:
Private ReadOnly Property GuestID1() as Int32
Get
Return Request.QueryString("id")
End Get
End Property
One of the benefits of doing this is to perform any checks on the value before using it, such as, is it an actual number that is stored in Request.QueryString("id"), or is the user allowed to have access to the entity represented by this id, or whatever else you can think of. When you do this, you'll need to change all references to _intGuestID1 to GuestID1.