VBA assigning to array - vba

In the code snippet I create an array of string and want to assign it to another.
Dim rfms(0) As String
rfms(0) = "X"
The next line is not working
Me.SelectedRfms = rfms
But when I created the next function:
Function ReturnTheArrayInParamter(p() As String) As String()
ReturnTheArrayInParamter = p
End Function
This is working:
Me.SelectedRfms = ReturnTheArrayInParamter(rfms)
The definition of Me.SelectedRfms is the next:
Private pSelectedRfms() As String
''''''''''''''''''''''
' SelectedRfms property
''''''''''''''''''''''
Public Property Get SelectedRfms() As String()
SelectedRfms = pSelectedRfms
End Property
Public Property Let SelectedRfms(value() As String)
pSelectedRfms = value
End Property
Can you explain why the first one is not working and why the second is working.

You cannot assign an array declared with a fixed size to a property, use:
ReDim rfms(0) As String
(The indirect function does not use a fixed size array)

Related

How to set 2 arguments on Let function in a class in vba (for excel)?

I am creating a Class in vba (for excel) to process blocks of data. After some manipulation of a text file I end up with blocks of data (variable asdatablock() ) which I want to process in a For Loop
I created my own Class called ClDataBlock from which I can get key data by a simple call of the property required. 1st pass seems to work and I am now trying to expand my Let function to 2 argument but it’s not working. How do I specify the 2nd argument?
Dim TheDataBlock As New ClDataBlock
For i = 0 to UBound(asdatablock)
asDataBlockLine = Split(asdatablock(i), vbLf) ‘ split block into line
TheDataBlock.LineToProcess = asDataBlockLine(5) ‘allocate line to process by the class
Dvariable1 = TheDataBlock.TheVariable1
‘and so on for the key variables needed base don the class properties defined
Next i
In the Class Module the Let function takes 2 arguments
Public Property Let LineToProcess(stheline As String, sdataneeded As String)
code extract of what I am looking at -
'in the class module
Dim pdMass As Double
Private pthelineprocessed As String
Public Property Let LineToProcess(stheline As String, sdataneeded As String)
pthelineprocessed = DeleteSpaces(Replace(stheline, vbLf, ""))
Dim aslinedatafield() As String
Select Case sdataneeded
'THIS IS AN EXTRACT FROM THE FUNCTION
'THERE ARE AS NUMBER OF CASES WHICH ARE DEALT WITH
Case Is = "MA"
aslinedatafield() = Split(pthelineprocessed, " ")
pdbMass = CDbl(aslinedatafield(2))
End select
End function
Public Property Get TheMass() As Double
TheMass = pdMass
End Property
'in the "main" module
Dim TheDataBlock As New ClDataBlock
For i = 0 to UBound(asdatablock)
TheDataBlock.LineToProcess = asDataBlockLines(5) 'Need to pass argument "MA" as well
dmass = TheDataBlock.TheMass
'and so on for all the data to be extracted
Next i
When a Property has 2 or more arguments, the last argument is what is getting assigned. In other words, the syntax is like this:
TheDataBlock.LineToProcess("MA") = asDataBlockLine(5)
This means you need to change the signature of your property:
Public Property Let LineToProcess(sdataneeded As String, stheline As String)

VBA. Access to an array element of the Variant. An array is a class property

I have a class with an ArrSignalCabel variable. In this variable I write an array of objects.
Property Get bottom of my class returns only an array. And I do not have access to the array element.
Option Explicit
Private ArrSignalCabel As Variant
Property Let ArrSignalCab(ByVal ArrValue As Variant)
ArrSignalCabel = ArrValue
End Property
Property Get ArrSignalCab() As Variant
ArrSignalCab = ArrSignalCabel
End Property
Public Property Get ArrSignalCabIn(index As Integer) As Variant ' not work
ArrSignalCabIn(index) = ArrSignalCabel(index)
End Property
////////////////
NameObjTM2 = TempPanel.ArrCabelPan(i).ArrSignalCabIn(0) ' not work
NameObjTM3 = TempPanel.ArrCabelPan(i).ArrSignalCab ' work
NameObjTM4= NameObjTM3(0).NameSig ' work
PS:
TempPanel - an object that contains an array of objects(ArrCabelPan).
ArrCabelPan - the class structure is identical to that described.
Have you tried ArrSignalCabIn = ArrSignalCabel(index)?
The name of the property should match what you declared in the Property Get, like Function.
I find answer
Public Property Get ArrSignalCabIn(Index As Integer) As Variant
If (ArrSignalCabel(Index) Is Nothing) Then Set ArrSignalCabel(Index) = New Signal
Set ArrSignalCabIn = ArrSignalCabel(Index)
End Property
Thanks to those who helped

Array of variables declared as string

I have a query regarding creating an array of variables declared as string.
Below is my code. On debugging, the variables show no value.
Need help..
Module Module1
Public Status, PartStat, HomeStat, ClampStat, SldCylStat, PrsCylP1Stat,
PrsCylP2Stat, PrsCylP3Stat, PrsCylP4Stat, PunchStat, SysInProc, Home1,
Home2, Home3, CyclTim, TrqP1Stat, TrqP2Stat, TrqP3Stat, TrqP4Stat,
AngleP1Stat, AngleP2Stat, AngleP3Stat, AngleP4Stat As String
Function AutoReadStatus()
Dim StatArray = {HomeStat, ClampStat, SldCylStat, Home1, PrsCylP4Stat,
PrsCylP2Stat, Home2, PrsCylP3Stat, PrsCylP1Stat, Home3, PunchStat,
AngleP4Stat, AngleP2Stat, AngleP3Stat, AngleP1Stat, TrqP4Stat,
TrqP2Stat, TrqP3Stat, TrqP1Stat}
Status = ReadMultiReg(FormAuto.SP1, "03", "1258", "0013")
For i = 0 To ((Status.Length / 4) - 1)
StatArray(i) = CInt("&H" & Status.Substring(i * 4, 4))
Next
Return Nothing
End Function
End Module
It is not even showing the index of any variable from above array..
Label1.Text = Array.IndexOf(StatArray, SldCylStat)
When you assign a new value to the item inside the array, you assign a new value to the item inside the array (pun intended).
What that means is that item's array now reference the string (or rather the Integer implicitely converted to string as you don't have Option Strict On) you gave and the precedent reference (on your public field) is dropped.
Test this sample code and I think you will understand
Public item As String
Sub Test()
Dim array = {item}
Console.WriteLine(array(0) Is item) ' True
array(0) = "new value"
Console.WriteLine(array(0) Is item) ' False
End Sub
You can see now array(0) reference another object than the one referenced by the item field
As for how to solve it,yYou could pass all those string ByRef that way assignment inside the method would reflect outside of it but that would be tedious.
A "better" way IMO, would be to make a type (a Class) to hold all those string and pass an instance of that type to your method, that way you just mutate the same existing object.
Quick, contrived example :
Class SomeType
Property Item As String
End Class
Sub Test(instance As SomeType)
instance.Item = "new value"
End Sub
' Usage
Dim sample As New SomeType
' here sample.Item is Nothing
Test(sample)
' here sample.Item is "new value"

Looping through a list gives me repeation of items, xml serializer

I have two lists. Both are made of structures I have defined, and this loop is meant to convert the two. I.e., convert and then add to the second list of the other type. Here is what I have:
Dim tempList As New List(Of CameraTemplateProduct)
tempList.Clear()
For j As Integer = 0 To EditCamerasNEW.templateList.Count - 1
'Set up product object.
Dim temp As New CameraTemplateProduct()
'equal properties
temp.Name = EditCamerasNEW.templateList.Item(j).mac
temp.Bitrate = EditCamerasNEW.templateList.Item(j).bitrate
temp.CamDate = EditCamerasNEW.templateList.Item(j).camdate
temp.CamTime = EditCamerasNEW.templateList.Item(j).camtime
temp.Encoder = EditCamerasNEW.templateList.Item(j).encoder
temp.FPS = EditCamerasNEW.templateList.Item(j).fps
temp.Hostname = EditCamerasNEW.templateList.Item(j).hostname
temp.MD = CBool(EditCamerasNEW.templateList.Item(j).MDen)
temp.OSD = CBool(EditCamerasNEW.templateList.Item(j).OSD)
temp.Resolution = EditCamerasNEW.templateList.Item(j).res
tempList.Add(temp)
Next
'Serialize object to a text file.
Dim x As New XmlSerializer((tempList.GetType))
x.Serialize(objStreamWriter, tempList)
Very straight forward. Copy over each property, then add it to the list. When I'm in the loop, temp's values copy over well. The values are exactly the same as the item in TemplateList. When I step through the loop, tempList is exactly what I expect it to be. Three distinct structures. But after wards I get the exact same number of items, but copies of one of them in my list.
However, the line right after the next loop, the tempList instead is the exact same count as templateList, but each value is exactly the same. So every item has the same name, MD, encoder, etc value.
What I've tried: I've tried changing the line after the next to
Dim x As New XmlSerializer((GetType(List(Of CameraTemplateProduct))))
but it gives the same result.
What am I doing wrong? Is there anything the "templist.gettype" is doing to cause this?
EDIT:
I have found that the temp is not changing property values when it loops, so it stays stuck at the first loop values. Is there a better way to clear or set it? I tried setting it to Nothing, but it gave me NULL assignment error.
EDIT2: So following the comments,
I checked to see if the templatelist items were changing. I added a
Dim test = EditCamerasNEW.templateList(j).mac
for each loop to see that it changed. The value did change. I set the rest of the "templatelist.item(j).x" to just "templatelist(j)" as above, but it didn't stop it from creating a list of repeated values.
EDIT3 Tried the below method to no avail. I'm thinking it is possibly when I create the templist of my class. It may not know how to create a list of the product? I will take any help on that.
tempList.Add(New CameraTemplateProduct With {.Name = EditCamerasNEW.templateList(j).mac, _
.Bitrate = EditCamerasNEW.templateList(j).bitrate, _
.CamDate = EditCamerasNEW.templateList(j).camdate, _
.CamTime = EditCamerasNEW.templateList(j).camtime, _
.Encoder = EditCamerasNEW.templateList(j).encoder, _
.FPS = EditCamerasNEW.templateList(j).fps, _
.Hostname = EditCamerasNEW.templateList(j).hostname, _
.MD = EditCamerasNEW.templateList(j).MDen, _
.OSD = EditCamerasNEW.templateList(j).OSD, _
.Resolution = EditCamerasNEW.templateList(j).res})
Here's a portion of the CameraTemplateProduct definition. It's pretty normal:
Public Class CameraTemplateProduct
Public Shared strhostname As String
Public Shared bOSD As Boolean
Public Shared strbitrate As String
Public Shared strencoder As String
Public Shared bMDen As Boolean 'motion detection enabled
Public Shared strres As String
Public Shared intfps As Integer
Public Shared strcamtime As String
Public Shared strcamdate As String
Public Shared strTemplateName As String
'grab properties
Public Property Name() As String
Get
Name = strTemplateName
End Get
Set(ByVal Value As String)
strTemplateName = Value
End Set
End Property
Public Property Hostname() As String
Get
Hostname = strhostname
End Get
Set(ByVal Value As String)
strhostname = Value
End Set
End Property
Public Property OSD() As Boolean
Get
OSD = bOSD
End Get
Set(ByVal Value As Boolean)
bOSD = Value
End Set
End Property
' code continues

Passing Enum Array or list to Function

I want to compare an enum array to single enum instance.
Introduction
I have a class with an enum type array\list
Public Enum InvalidEmailType
Multiple_Updates
Period_Before_At_Sign
Missing_Dot_Com
End Enum
Public Class CustomerClass
Public CustomerName As String
Public ErrorTypeList = [Enum].GetValues(GetType(InvalidEmailType))
Public ErrorDescription As String
End Class
Depending on what values are added to the list, I want to run specific code.
In order to do this I compare the entire list to a single instance:
If UpdateCustomer.MatchErrorType(customer.ErrorTypeList, InvalidEmailType.Trailing_Period) = True Then
'Run Code
End If
Inside the function I compare the entire list against the single instance.
In other words, I loop through the entire list inside the class and check if the value is there:
Public Shared Function MatchErrorType(CustomerErrortypeList As List(Of InvalidEmailType), EmailError As InvalidEmailType) As Boolean
MatchErrorType = False
Dim Found As InvalidEmailType = CustomerErrortypeList.Where(Function(match) match.ToString = EmailError.ToString).OrderByDescending(Function(match) match.ToString).FirstOrDefault()
If Found > 0 Then
MatchErrorType = True
End If
End Function
Here is the problem:
How do I declare the array\list in the function parameters?
List(Of InvalidEmailType) does not work, as I get a cast error
Unable to cast object of type 'EmailValidationReport.InvalidEmailType[]' to type 'System.Collections.Generic.List`1[EmailValidationReport.InvalidEmailType]'
Set ErrorTypeList to a List(of InvalidEmailType) instead of array.
Public ErrorTypeList = [Enum].GetValues(GetType(InvalidEmailType)) _
.Cast(of InvalidEmailType)().ToList()
or
Dim list = customer.ErrorTypeList.Cast(of InvalidEmailType)().ToList()
If UpdateCustomer.MatchErrorType(list, InvalidEmailType.Trailing_Period) Then
'Run Code
End If
Since you aren't doing anything that is specific to List or Array, you can make your method signature take in an IEnumerable instead of a List. This should be able to handle both List and Array (and a few more types as well).
Public Shared Function MatchErrorType(CustomerErrortypeList As IEnumerable(Of InvalidEmailType), EmailError As InvalidEmailType) As Boolean
Dim Found As InvalidEmailType = CustomerErrortypeList.Where(Function(match) match.ToString = EmailError.ToString).OrderByDescending(Function(match) match.ToString).FirstOrDefault()
MatchErrorType = (Found > 0)
End Function