Variable in Array Variable - vb.net

if i generate a label dynamically i can change the text as followed, variable is a string:
Form.Controls(variable).text = "test"
I now have a sub that will create some and will get some information out of arrays. I have a lot of them. I only want the function for tat specific array. I do not want a case or if. Thats why i was wondering if i can use a variable in the array variable. Sounds strange, here is what i mean:
Public TestArray() as String
Public Sub BuildStructure(ByVal Shelf As String)
Dim XMax as Integer
XMax = TestArray.GetLength(1)
End Sub
But instead of TestArray beeing hardcoded i want it to be replaced with Shelf. So whatever gets send into the sub will change the array that i'm using.
Is that possible some how or is the way totally wrong?
Thanks

You can use an arraylist object that you can easily add and remove items from at runtime. Here's the MSDN page: http://msdn.microsoft.com/en-us/library/7x4b0a97.aspx
Public TestArray As New ArrayList
Public Sub BuildStructure(ByVal Shelf As String)
TestArray.Add(Shelf)
End Sub
If you need an array, you can always call the .ToArray method on the ArrayList

Related

How to assign a value to a variable of type Double, that has been passed as Object?

I am trying to assign a value to global variable, which has a Property of type Double. This Property is passed as Object and the assignment fails.
In the example code below, the value is never assigned to the actual object, but only locally:
Public Class Form1
Friend Home As New Building
Private Sub AssignValues() Handles Me.Load
'Objects of different types are added to a list
Dim listObjects As New List(Of Object)
listObjects.Add(Home.Surface)
'All the Objects in listObjects are assigned a value that
'is stored as String
For Each o As Object In listObjects
SetProperty(o, "45.6")
Debug.Print("Surface = " & Home.Surface.ToString)
Next
End Sub
Private Sub SetProperty(ByRef Variable As Object, ByVal Value As String)
Select Case Variable.GetType
Case GetType(Double)
Variable = CDbl(Value)
Case Else
'...
End Select
End Sub
End Class
Public Class Building
Dim _surface As Double = 0
Public Property Surface As Double
Get
Return _surface
End Get
Set(ByVal value As Double)
_surface = value
End Set
End Property
End Class
The program invariably outputs Surface = 0 instead of 45.6. What am I doing wrong?
I tried to pass the Variable as reference, as suggested here, but without success. I also read about using Reflection, but there ought to be something simpler than that...
When your adding home.surface to the list, your adding a copy of the double to the list and then adjusting that copy. Stick a watch on "o" and see how it changes whilst home.surface remains the same.
If you want to use reflection, try something along these lines.
Dim prop As Reflection.PropertyInfo = o.GetType().GetProperty("Surface")
prop.SetValue(o, 45.6)
With Variable.GetType you will get always Object, because this is the type of Variable. What you can do with an Object is converting/casting it into a different type (like Double).
The best way to determine the "original type" from where the Object comes would be including an additional variable telling it. Another option might be converting the given Object into the target Type and see if it is not nothing/does not trigger an error. But this second option is not too accurate, mainly when dealing with "equivalent types" like Doubles/Integers.

Variable Value Passing to another Form, VB.NET

I do have Two Public Variables, each are from two different forms..
Form1.VB
Public UserNo As String
Form2.VB
Public MyUserNo As String
On my Form2.VB File, I assign value to the UserNo of Form1.VB
Form1.UserNo = MyUserNo
Whenever I access the Form1.VB, the Value of the MyUserNo got empty, What should I do? Both Forms are not closed.
I also tried to re-assign the value when I need to use it on the Form1.VB
UserNo = Form2.MyUserNo
First Correct is Syntax is:
Form1.VB
Public UserNo As String
Form2.VB
Public MyUserNo As String
In Form1
UserNo=Form2.MyUserNo
Second Thing:
First you should store some value in MyUserNo before storing it into UserNo.
That's why you are getting empty value.
Make the variable static/Shared and try again,it should work.
You can have more than one instance of a form, you know. Forms are objects, just like anything else. You need a variable in each form to hold a reference to the instance of each form that you are using.
If you don't call InitializeComponent(), your complete GUI is not going to render.
...
InitializeComponent()
Form1.UserNo = MyUserNo
...
Try this:
[Form1.UserNo = form2.MyUserNo]
it work
add it to form what you want value in next form
Function getvariable()
Return (VARIABLE)
End Function
In next form to get VARIABLE
VARIABLE2 = Form.getvariable()
Use variable value as Public
For Example
In Form1:
Public Str1 as String
So in Form2 you can use:
Str2=Form1.Str1
'In frmMain i Start frmBase
Dim f As New frmBase
f.Text = "New caption for frmBase"
f.ShowDialog(Me)
'in frmBase i read and write a textbox
Dim str As String = CType(Me.Owner, frmMain).txtRicetta.Text
Console.WriteLine(str)
CType(Me.Owner, frmMain).txtRicetta.Text = "12345"
Console.WriteLine(CType(Me.Owner, frmMain).txtRicetta.Text)
What you need to do is create your variables in a module as private, then generate some assessors for them.
Example:
Module modVariables
Private strUserNoSTR as String = New String(String.Empty)
Public Property getUserNoSTR() As String
Get
Return strUserNoSTR
End Get
Set(ByVal strUserNo As String)
strUserNoSTR = strUserNo
End Set
End Property
Private strMyUserNoSTR As String = New String(String.Empty)
Public Property getMyUserNoSTR As String
Get
Return strMyUserNoSTR
End Get
Set(ByVal strMyUserNo As String)
strMyUserNoSTR = strMyUserNo
End Set
End Property
End Module
After you generate the getter and setter public methods you can notice that your two private variables are within them, when you create the variables they are accessible from any form.
The reason why you keep losing the variables value is because when you try to access its value from another form (basically you're calling it from another class) the compiler has to create a new instance of that variable and when that happened the variable is set back to its original value which is of type empty string. Calling them from a module keeps them from being re-instantiated.
How To Use Them:
To get the value of strMyUserNo you call the getter of strMyUserNoSTR:
TextBox.Text = getMyUserNoSTR
To set the value of strMyUserNoSTR:
getMyUserNoSTR = someValuePlacedInThisVariable 'This sets it's value.
TextBox.Text = getMyUserNoSTR 'Now it's value is someValuePlacedInThisVariable.

vb.net Array resizing inside a function

I am running into an issue with Array resizing in vb.net. I sort of understand why the issue is coming up but I'm not sure how to get around it. Basically, I have a class that has an array of objects being passed to it. I'm trying to have a sub resize the array and add another object to it. However, once it's done, the original object does not get updated.
Optimally I would like something like this.
Sub Main()
Dim parent As New Parent
Dim first As New Child()
Dim second As New Child()
Dim children As Child() = New Child() {first, second}
parent.children = children
setChildren(getChildren(parent))
End Sub
Private Function getChildren(parent As Parent) As Child()
Return parent.children
End Function
Private Sub setChildren(ByRef testArray As Child())
testArray = New Child(3) {}
End Sub
Because setChildren accepts its testArray parameter by ref, it must be given a variable or field, rather than a property or function return. If Parent.children is a field, rather than a property, one could call setChildren(parent.children);. Alternatively, one could make Parent.children hold a type which itself holds a reference to an array; the two built-in types which meet that criterion would be List(Of Child) and Child()(). Incidentally, I'd suggest changing your identifier names so that type names and variable names are clearly distinct (vb.net is not case-sensitive).
Based on your requirements I think the ReDim Statement is what you are after:
Private Sub setChildren(ByRef testArray As Child())
ReDim Preserve testArray(3)
End Sub
The Preserve Statement will copy the contents of testArray into the newly created array.
Since you are using arrays, you need to ReDim the array to add another element.
Private Sub setChildren(ByRef testArray As Child())
Dim arrayLength as Int = testArray.Length 'total number of elements in array
ReDim Preserve testArray(arrayLength)
testArray(arrayLength) = New Child {}
End Sub
Edit: Forget the Preserve keyword

Set a type in VBA to nothing?

I have defined a variable with an own type, say
Dim point As DataPoint
Public Type DataPoint
list as Collection
name as String
number as Integer
End Type
and I want to delete all values of the variable point at once. If it was a class, I would just use Set point = New DataPoint, or set Set point = Nothing, but how can I proceed if it's a type?
You can benefit from the fact that functions in VB have an implicit variable that holds the result, and that contains the default type value by default.
public function GetBlankPoint() as DataPoint
end function
Usage:
point = GetBlankPoint()
The standard way is to reset each member to its default value individually. This is one limitation of user-defined types compared to objects.
At the risk of stating the obvious:
With point
Set .list = Nothing
.name = ""
.number = 0
End With
Alternatively, you can create a "blank" variable and assign it to your variable each time you want to "clear" it.
Dim point As DataPoint
Dim blank As DataPoint
With point
Set .list = New Collection
.list.Add "carrots"
.name = "joe"
.number = 12
End With
point = blank
' point members are now reset to default values
EDIT: Damn! Beaten by JFC :D
Here is an alternative to achieve that in 1 line ;)
Dim point As DataPoint
Dim emptyPoint As DataPoint
Public Type DataPoint
list As Collection
name As String
number As Integer
End Type
Sub Sample()
'~~> Fill the point
Debug.Print ">"; point.name
Debug.Print ">"; point.number
point.name = "a"
point.number = 25
Debug.Print ">>"; point.name
Debug.Print ">>"; point.number
'~~> Empty the point
point = emptyPoint
Debug.Print ">>>"; point.name
Debug.Print ">>>"; point.number
End Sub
SNAPSHOT
One-liner:
Function resetDataPoint() As DataPoint: End Function
Usage:
point = resetDataPoint()
Another option is to use the reserved word "Empty" such as:
.number= Empty
The only issue is that you will need to change the number from integer to variant.
Using classes in VBA is usually a good practice in case it is not a single purpose solution or the class do not contain too many private attributes because if you want to adhere on OOP rules and keep your class safe, you should declare all the Let and Get properties for all private attributes of class. This is too much coding in case you have more than 50 private attributes. Another negative side of using classes in excel is fact, that VBA do not fully support the OOP. There is no polymorfism, overloading, etc.) Even you want to use an inheritance, you have to declare all the attributes and methods from the original class in the inherited class.
So in this case I would prefer the solution suggested by Jean-François Corbett or GSeng, i.e. to assign an empty variable of the same UDT as the variable you want to clear or to use a function which to me seems little bit more elegant solution because it will not reserve permanent memory for the emtpy variable of your UDT type.
For that is better to use classes, you can declare a class module with the name of your type, then declare all of your members as public, then automatically you can set to nothing and new for create and delete instances.
syntax will be somthing like this after you create the class module and named like your type:
'
Public List as Collection
Public Name as String
Public Number as Long
Private Sub Class_Initialize()
'Here you can assign default values for the public members that you created if you want
End Sub

Sub / Function array parameter altered

I have a Sub with an array of strings as parameter:
Private Sub des(ByVal array() As String)
Dim i As Integer
For i = 0 To UBound(array)
array(i) = "hy"
Next
End Sub
When I call the function inside my main function, the value of str changes even if the array is passed to the function ByVal:
Dim str() As String
str = {"11111", "22222", "33333", "44444", "5555", "66666"}
des(str)
I tried making a copy of the array in the Sub, but it still changes in the main function.
Private Sub des(ByVal array() As String)
Dim i As Integer
Dim array2() As String
array2 = array
For i = 0 To UBound(array)
array(i) = "hy"
Next
End Sub
I read on a site that you cannot pass arrays ByVal. Is this true? If so, how should I proceed?
Try this:
Dim i As Integer
Dim array2() As String
array2 = array.Clone()
For i = 0 To UBound(array2)
array2(i) = "hy"
Next
The key difference is the .Clone(), that actually makes a shallow copy of array, and changing the values in array2 will no longer affect your str value in the main code.
Arrays are reference types. That means that when you pass an Array to your function, what is passed is always a reference, not a copy of the array. The Array in your function refers to the same array object as the Array in your calling code.
The same thing happens when you do the assign (it is not a copy!) in your second example: all you've done is make yet another reference to the same object. That is why Boeckm's solution works -- the Clone() call does make a new array and assign it values which are copies of the values in the original array.
In Visual Basic .NET, regarding arrays as parameters, there are two important rules you have to be aware of:
Arrays themselves can be passed as ByVal and ByRef.
Arrays' elements can always be modified from the function or subroutine.
You already know that you can modify the elements of an array inside a subprocess (subroutine or function), no matter how that array is defined as parameter inside that subprocess.
So, given these two subroutines:
Private Sub desval(ByVal array() As String)
array = {}
End Sub
Private Sub desref(ByRef array() As String)
array = {}
End Sub
And this very simple auxiliary subroutine (here I'll use the Console):
Private Sub printArr(ByVal array() As String)
For Each str In array
Console.WriteLine(str)
Next
End Sub
you can do these simple tests:
Dim arr1() as String = {"abc", "xyz", "asdf"}
Console.WriteLine("Original array:")
printArr(arr1)
Console.WriteLine()
Console.WriteLine("After desval:")
desval(arr1)
printArr(arr1)
Console.WriteLine()
Console.WriteLine("After desref:")
desref(arr1)
printArr(arr1)
I read on a site that you cannot pass arrays ByVal. Is this true?
No, that is not true.
An array in the .NET framework is a reference type. When you create an array, an object of System.Array will be created and its reference is assigned to the reference variable.
When you call a des method, the reference of the array object will be passed. In des method, ByVal parameter is a reference parameter variable of type System.Array, and it receive a copy of reference of an array object.
MSDN article - Passing Arguments by Value and by Reference (Visual Basic)