Misunderstanding of collection - vba

Based on this post What are the benefits of using Classes in VBA? I've made a bit of code.
The first class CarteID
Option Explicit
Private agePersonne As Long
Private nomPersonne As String
Public Property Get glAgePersonne() As Long
glAgePersonne = agePersonne
End Property
Public Property Let glAgePersonne(lAgePersonne As Long)
agePersonne = lAgePersonne
End Property
Public Property Get glNomPersonne() As String
glNomPersonne = nomPersonne
End Property
Public Property Let glNomPersonne(lNomPersonne As String)
nomPersonne = lNomPersonne
End Property
Then the second class ProcessCarteID
Option Explicit
Private colCartesID As Collection
Public Property Get gsCartesID() As Collection
Set gsCartesID = colCartesID
End Property
Public Property Set gsCartesID(sCartesID As Collection)
Set colCartesID = sCartesID
End Property
Function RecupAgeMoyen() As Double
Dim cid As CarteID
Dim moyenneAge As Double
moyenneAge = 0
For Each cid In colCartesID
moyenneAge = moyenneAge + cid.glAgePersonne
Next cid
moyenneAge = moyenneAge / colCartesID.Count
RecupAgeMoyen = moyenneAge
End Function
And the module :
Option Explicit
Function PopulateArray() As Collection
Dim colInfos As New Collection
Dim cid As CarteID
Set cid = New CarteID
cid.glNomPersonne = "Fred"
cid.glAgePersonne = 21
colInfos.Add cid
Set cid = New CarteID
cid.glNomPersonne = "Julie"
cid.glAgePersonne = 18
colInfos.Add cid
Set cid = New CarteID
cid.glNomPersonne = "Jean"
cid.glAgePersonne = 25
colInfos.Add cid
Set PopulateArray = colInfos
End Function
Sub TestAgeMoyen()
Dim pci As ProcessCarteID
Set pci = New ProcessCarteID
Set pci.gsCartesID = PopulateArray()
Debug.Print pci.RecupAgeMoyen()
End Sub
In the function RecupAgeMoyen() I tried For Each cid In colCartesID and For Each cid In gsCartesID. Both worked.
I just wanted to know why it worked also with gsCartesID because I am not sure to understand.
Thanks !

Related

Casting from class to interface in Excel VBA

In Excel 2013, I have two classes: LoadCase and LoadCombination, which implement interface ILoadCase.
The declaration for ILoadCase is:
Option Explicit
'' Public properties
Public Property Get Name() As String
End Property
Public Property Let Name(ByVal value As String)
End Property
Public Property Get ID() As Long
End Property
Public Property Let ID(ByVal valus As Long)
End Property
And the (partial) implementations for both LoadCase and LoadCombination are:
Option Explicit
Implements ILoadCase
'' Public properties
Public Property Get ILoadCase_Name() As String
ILoadCase_Name = pName
End Property
Private Property Let ILoadCase_Name(ByVal value As String)
pName = value
End Property
Public Property Get ILoadCase_ID() As Long
ILoadCase_ID = pID
End Property
Private Property Let ILoadCase_ID(ByVal value As Long)
pID = value
End Property
I've omitted code which is irrelevant to the implementation of the interface.
I then have a class BeamForces, which contains results for a particular ILoadCase object:
Option Explicit
Public Fx As Double
Public Fy As Double
Public Fz As Double
Public Mx As Double
Public My As Double
Public Mz As Double
Public ParentLoadCase As ILoadCase
I thought that with this I'd be able to do something like this:
Set currentBeamForces = New BeamForces
With currentBeamForces
.Fx = forces(0)
.Fy = forces(1)
.Fz = forces(2)
.Mx = forces(3)
.My = forces(4)
.Mz = forces(5)
Set .ParentLoadCase = TargetLoadCase
End With
Where TargetLoadCase is either a LoadCase or a LoadCombination, but this gives me an error every time.
I've coded this like I would in .NET and just expected that it would work, but does casting to an interface not work in VBA? Or am I going wrong here somewhere?
EDIT
More details. I first call the following method:
Public Function LoadBeamForcesAtNode(ByVal TargetBeam As Beam, ByVal TargetNode As Node, Optional ByVal TargetLoadCases As Collection = Nothing) As Boolean
Dim i As Integer
Dim currentLoadCase As Variant
Dim targetBeamForces As BeamForces
If TargetLoadCases Is Nothing Then
For Each currentLoadCase In Me.LoadCases.Items
Call TargetLoadCases.Add(currentLoadCase)
Next
For Each currentLoadCase In Me.LoadCombinations.Items
Call TargetLoadCases.Add(currentLoadCase)
Next
End If
'On Error GoTo ExitPoint
For Each currentLoadCase In TargetLoadCases
Set targetBeamForces = InstantiateBeamForces(TargetBeam, TargetNode, currentLoadCase)
If TargetNode Is TargetBeam.Node1 Then
Set TargetBeam.Forces1 = targetBeamForces
Else
Set TargetBeam.Forces2 = targetBeamForces
End If
Next
LoadBeamForcesAtNode = True
ExitPoint:
End Function
Where TargetLoadCases is a collection which can contain both LoadCase and LoadCombination objects.
The problem occurs in InstantiateBeamForces, the code for which is
Private Function InstantiateBeamForces(ByVal TargetBeam As Beam, ByVal TargetNode As Node, ByVal TargetLoadCase As Variant) As BeamForces
Dim forces(5) As Double
Dim currentBeamForces As BeamForces
Call Me.output.GetMemberEndForces(TargetBeam.ID, IIf(TargetNode Is TargetBeam.Node1, 0, 1), TargetLoadCase.ILoadCase_ID, forces, 0)
Set currentBeamForces = New BeamForces
With currentBeamForces
.Fx = forces(0)
.Fy = forces(1)
.Fz = forces(2)
.Mx = forces(3)
.My = forces(4)
.Mz = forces(5)
Set .ParentLoadCase = TargetLoadCase
End With
Set InstantiateBeamForces = currentBeamForces
End Function
Which creates a new BeamForces object and populates it with the values returned by the ...GetMemberEndForces(...) API COM call.
The problem is that the .ParentLoadCase property is nothing after the assignment, so I'm assuming an invalid cast...
** EDIT 2 **
Here is a screenshot of TargetLoadCase when I put a breakpoint in InstantiateBeamForces.
The ILoadCase member is Nothing, but I don't get why. Could this be the cause of the problem?

How to create a compound object in VBA?

I cannot make my way through the Microsoft help, which is great provided you know what the answer is already, so I'm stuck.
Is it possible for me to create my own compound object (I assume that this is the term) such that, for example, the object could be a person and would have the following sub-classes:
Firstname - String
Surname - String
Date of birth - Datetime
Gender - String (M/F accepted)
Height - Real number
Sorry if it seems like a very basic question (no pun intended) but I haven't used Visual Basic for a long time, and Microsoft Visual Basic was never my forté.
You should consider using class modules instead of types. Types are fine, but they're limited in what they can do. I usually end up converting my types to classes as soon as I need some more function than a type can provide.
You could create a CPerson class with the properties you want. Now if you want to return a FullName property, you can write a Property Get to return it - something you can't do with a type.
Private mlPersonID As Long
Private msFirstName As String
Private msSurname As String
Private mdtDOB As Date
Private msGender As String
Private mdHeight As Double
Private mlParentPtr As Long
Public Property Let PersonID(ByVal lPersonID As Long): mlPersonID = lPersonID: End Property
Public Property Get PersonID() As Long: PersonID = mlPersonID: End Property
Public Property Let FirstName(ByVal sFirstName As String): msFirstName = sFirstName: End Property
Public Property Get FirstName() As String: FirstName = msFirstName: End Property
Public Property Let Surname(ByVal sSurname As String): msSurname = sSurname: End Property
Public Property Get Surname() As String: Surname = msSurname: End Property
Public Property Let DOB(ByVal dtDOB As Date): mdtDOB = dtDOB: End Property
Public Property Get DOB() As Date: DOB = mdtDOB: End Property
Public Property Let Gender(ByVal sGender As String): msGender = sGender: End Property
Public Property Get Gender() As String: Gender = msGender: End Property
Public Property Let Height(ByVal dHeight As Double): mdHeight = dHeight: End Property
Public Property Get Height() As Double: Height = mdHeight: End Property
Public Property Get FullName() As String
FullName = Me.FirstName & Space(1) & Me.Surname
End Property
Then you can create a CPeople class to hold all of your CPerson instances.
Private mcolPeople As Collection
Private Sub Class_Initialize()
Set mcolPeople = New Collection
End Sub
Private Sub Class_Terminate()
Set mcolPeople = Nothing
End Sub
Public Property Get NewEnum() As IUnknown
Set NewEnum = mcolPeople.[_NewEnum]
End Property
Public Sub Add(clsPerson As CPerson)
If clsPerson.PersonID = 0 Then
clsPerson.PersonID = Me.Count + 1
End If
mcolPeople.Add clsPerson, CStr(clsPerson.PersonID)
End Sub
Public Property Get Person(vItem As Variant) As CPerson
Set Person = mcolPeople.Item(vItem)
End Property
Public Property Get Count() As Long
Count = mcolPeople.Count
End Property
Public Property Get FilterByGender(ByVal sGender As String) As CPeople
Dim clsReturn As CPeople
Dim clsPerson As CPerson
Set clsReturn = New CPeople
For Each clsPerson In Me
If clsPerson.Gender = sGender Then
clsReturn.Add clsPerson
End If
Next clsPerson
Set FilterByGender = clsReturn
End Property
With this class, you can For Each through all the instances (google custom class and NewEnum to see how to do that). You can also use a Property Get to return a subset of the CPerson instances (females in this case).
Now in a standard module, you can create a couple of CPerson instances, add them to your CPeople instance, filter them, and loop through them.
Public Sub FillPeople()
Dim clsPerson As CPerson
Dim clsPeople As CPeople
Dim clsFemales As CPeople
Set clsPeople = New CPeople
Set clsPerson = New CPerson
With clsPerson
.FirstName = "Joe"
.Surname = "Blow"
.Gender = "M"
.Height = 72
.DOB = #1/1/1980#
End With
clsPeople.Add clsPerson
Set clsPerson = New CPerson
With clsPerson
.FirstName = "Jane"
.Surname = "Doe"
.Gender = "F"
.Height = 62
.DOB = #1/1/1979#
End With
clsPeople.Add clsPerson
Set clsFemales = clsPeople.FilterByGender("F")
For Each clsPerson In clsFemales
Debug.Print clsPerson.FullName
Next clsPerson
End Sub
There's defintely more learning curve to creating classes, but it's worth it in my opinion.
I think you need to use TYPE syntax, like this:
TYPE person
Firstname As String
Surname As String
Date_of_birth As Date ' instead of Datetime
Gender As String '(M/F accepted)
Height As Single 'instead of Real number
END TYPE
Sub Test()
Dim aTest As person
End Sub

Retrieve items in collection (Excel, VBA)

I'm getting a Type Mismatch-error, when trying to retrieve items from my collection.
What I mainly want to do, is to collect all customers within as collection, and past all results on my ListBox for visualization. The reason why I'm using a class-module is due to the fact, that UDT are pasting an error: "Only user-defined types defined in public object modules can be coerced to or from a variant or passed to late-bound functions". So I started programming all properties in classes instead, but I haven't really worked with classes before, so it's pretty new to me.
I'm facing another issue; the .additem-property is limited to 9 columns (on the ListBox), and therefore I'd like to use another method for this. Array is unlimited, and rowsources are limited to 256 or 255. I'd like 14 columns to be shown on the ListBox, and furthermore have the ability to expand if needed later on.
ListView aren't really an option due to the fact, that many computers doesn't have this reference integrated.
Class-module. "clsCustomers"
Option Explicit
Private cID As String
Private cCustomerName As String
Private cCompanyName As String
Private cFullName As String
Private cCVR As Long
Private cType As String
Private cGroup As String
Private cCountry As String
Private cStreet As String
Private cZipcode As Variant
Private cCity As String
Private cPhoneNum As Long
Private cMobileNum As Long
Private cEmail As String
Private cInvoiceEmail As String
Private cCreationDate As Date
Private cLastChange As Date
Public Property Get customerID() As String
customerID = cID
End Property
Public Property Let customerID(value As String)
cID = value
End Property
Public Property Get customerName() As String
customerName = cCustomerName
End Property
Public Property Let customerName(value As String)
cCustomerName = value
End Property
Public Property Get customerCompanyName() As String
customerCompanyName = cCompanyName
End Property
Public Property Let customerCompanyName(value As String)
cCompanyName = value
End Property
Public Property Get customerFullName() As String
customerFullName = cFullName
End Property
Public Property Let customerFullName(value As String)
cFullName = value
End Property
Public Property Get customerCVR() As Long
customerCVR = cCVR
End Property
Public Property Let customerCVR(value As Long)
cCVR = value
End Property
Public Property Get customerType() As String
customerType = cType
End Property
Public Property Let customerType(value As String)
cType = value
End Property
Public Property Get customerGroup() As String
customerGroup = cGroup
End Property
Public Property Let customerGroup(value As String)
cGroup = value
End Property
Public Property Get customerCountry() As String
customerCountry = cCountry
End Property
Public Property Let customerCountry(value As String)
cCountry = value
End Property
Public Property Get customerStreet() As String
customerStreet = cStreet
End Property
Public Property Let customerStreet(value As String)
cStreet = value
End Property
Public Property Get customerZipcode() As Variant
customerZipcode = cZipcode
End Property
Public Property Let customerZipcode(value As Variant)
cZipcode = value
End Property
Public Property Get customerCity() As String
customerCity = cCity
End Property
Public Property Let customerCity(value As String)
cCity = value
End Property
Public Property Get customerPhoneNum() As Long
customerPhoneNum = cPhoneNum
End Property
Public Property Let customerPhoneNum(value As Long)
cPhoneNum = value
End Property
Public Property Get customerMobileNum() As Long
customerMobileNum = cMobileNum
End Property
Public Property Let customerMobileNum(value As Long)
cMobileNum = value
End Property
Public Property Get customerEmail() As String
customerEmail = cEmail
End Property
Public Property Let customerEmail(value As String)
cEmail = value
End Property
Public Property Get customerInvoiceEmail() As String
customerInvoiceEmail = cInvoiceEmail
End Property
Public Property Let customerInvoiceEmail(value As String)
cInvoiceEmail = value
End Property
Public Property Get customerCreationDate() As Date
customerCreationDate = cCreationDate
End Property
Public Property Let customerCreationDate(value As Date)
cCreationDate = value
End Property
Public Property Get customerLastChange() As Date
customerLastChange = cLastChange
End Property
Public Property Let customerLastChange(value As Date)
cLastChange = value
End Property
Module. "mExtendedCustomerDatabase". Here I collect my customers within the worksheet("CustomerDatabase").
Public CustomerCollection As New Collection
Sub CollectAllCustomers()
Dim tCustomers As clsCustomers
Dim i As Long
Dim wks As Worksheet
Set wks = ThisWorkbook.Worksheets("CustomerDatabase")
For i = 1 To wks.UsedRange.Rows.Count
Set tCustomers = New clsCustomers
With tCustomers
.customerID = "Kunde" & wks.Cells(i, CustomerDatabase.CustomerNumber).value
.customerName = wks.Cells(i, CustomerDatabase.InternRef).value
.customerCompanyName = wks.Cells(i, CustomerDatabase.CompanyName).value
.customerFullName = wks.Cells(i, CustomerDatabase.FirstName).value & wks.Cells(i, CustomerDatabase.LastName).value
.customerCVR = wks.Cells(i, CustomerDatabase.CVR).value
.customerType = wks.Cells(i, CustomerDatabase.customerType).value
.customerGroup = wks.Cells(i, CustomerDatabase.customerGroup).value
.customerCountry = wks.Cells(i, CustomerDatabase.Country).value
.customerStreet = wks.Cells(i, CustomerDatabase.Street).value
.customerZipcode = wks.Cells(i, CustomerDatabase.Zipcode).value
.customerCity = wks.Cells(i, CustomerDatabase.City).value
.customerPhoneNum = wks.Cells(i, CustomerDatabase.PhoneNum).value
.customerMobileNum = wks.Cells(i, CustomerDatabase.MobileNum).value
.customerEmail = wks.Cells(i, CustomerDatabase.Email).value
.customerInvoiceEmail = wks.Cells(i, CustomerDatabase.InvoiceEmail).value
.customerCreationDate = wks.Cells(i, CustomerDatabase.CreationDate).value
.customerLastChange = wks.Cells(i, CustomerDatabase.LastChangeDate).value
CustomerCollection.Add tCustomers, .customerID
End With
Next i
End Sub
Module. "mExtendedCustomerDatabase". Here I'd like to add my whole collection to my ListBox.
Sub FillListBox(sListName As String)
Dim wks As Worksheet
Set wks = ThisWorkbook.Worksheets("CustomerDatabase")
With frm_T1_Kundeoplysninger.Controls.Item(sListName)
.AddItem CustomerCollection.Item("Kunde1") 'Type Mismatch-error
End With
End Sub
To summarize. I'd like some guidelines on the easiest/fastest way to retrieve all items within my collection, and past them into my ListBox. Alternatives ways to do this, are accommodated aswell.
I manage to solve it. Converting my collection to an array, and setting my collection as inputparameter. Looping through my entire collection, and allocating it in an array. The issue seems to be related to .List-function, only allowing arrays as variant-datatype. It was solved; inspired by (http://www.iwebthereforeiam.com/iwebthereforeiam/2004/06/excel-vba-code-to-convert-coll.html).
Sub FillListBox(sListName As String)
With frm_T1_Kundeoplysninger.Controls.Item(sListName)
.List = ConvertCollectionToArray(CustomerCollection)
End With
Clearing:
Set CustomerCollection = Nothing
End Sub
Function ConvertCollectionToArray(cCustomers As Collection) As Variant()
Dim arrCustomers() As Variant: ReDim arrCustomers(0 To cCustomers.Count - 1, 16)
Dim i As Integer
With cCustomers
For i = 1 To .Count
arrCustomers(i - 1, 0) = .Item(i).customerID
arrCustomers(i - 1, 1) = .Item(i).customerName
arrCustomers(i - 1, 2) = .Item(i).customerCompanyName
arrCustomers(i - 1, 3) = .Item(i).customerFullName
arrCustomers(i - 1, 4) = .Item(i).customerCVR
arrCustomers(i - 1, 5) = .Item(i).customerType
arrCustomers(i - 1, 6) = .Item(i).customerGroup
arrCustomers(i - 1, 7) = .Item(i).customerCountry
arrCustomers(i - 1, 8) = .Item(i).customerStreet
arrCustomers(i - 1, 9) = .Item(i).customerZipcode
arrCustomers(i - 1, 10) = .Item(i).customerCity
arrCustomers(i - 1, 11) = .Item(i).customerPhoneNum
arrCustomers(i - 1, 12) = .Item(i).customerMobileNum
arrCustomers(i - 1, 13) = .Item(i).customerEmail
arrCustomers(i - 1, 14) = .Item(i).customerInvoiceEmail
arrCustomers(i - 1, 15) = .Item(i).customerCreationDate
arrCustomers(i - 1, 16) = .Item(i).customerLastChange
Next
End With
ConvertCollectionToArray = arrCustomers
End Function

Accessing custom property's value gives 'Out of Memory' error when value is null

I'm trying to create a custom property in an excel sheet, then retrieve its value. This is fine when I don't use an empty string, i.e. "". When I use the empty string, I get this error:
Run-time error '7':
Out of memory
Here's the code I'm using:
Sub proptest()
Dim cprop As CustomProperty
Dim sht As Worksheet
Set sht = ThisWorkbook.Sheets("control")
sht.CustomProperties.Add "path", ""
For Each cprop In ThisWorkbook.Sheets("control").CustomProperties
If cprop.Name = "path" Then
Debug.Print cprop.Value
End If
Next
End Sub
The code fails at Debug.Print cprop.value. Shouldn't I be able to set the property to "" initially?
With vbNullChar it works, sample:
Sub proptest()
Dim sht As Worksheet
Set sht = ThisWorkbook.Sheets("control")
' On Error Resume Next
sht.CustomProperties.Item(1).Delete
' On Error GoTo 0
Dim pathValue As Variant
pathValue = vbNullChar
Dim pathCustomProperty As CustomProperty
Set pathCustomProperty = sht.CustomProperties.Add("path", pathValue)
Dim cprop As CustomProperty
For Each cprop In ThisWorkbook.Sheets("control").CustomProperties
If cprop.Name = "path" Then
Debug.Print cprop.Value
End If
Next
End Sub
I think from the comments and the answer from Daniel Dusek it is clear that this cannot be done. The property should have at least 1 character to be valid, an empty string just isnt allowed and will give an error when the .Value is called.
So you Add this property with a length 1 or more string and you Delete the property again when no actual value is to be assigned to it.
As already mentioned it is not possible to set empty strings.
An easy workaround is to use a magic word or character, such as ~Empty (or whatever seems proof enough for you):
Dim MyProperty As Excel.CustomProperty = ...
Dim PropertyValue As String = If(MyProperty.Value = "~Empty", String.Empty, MyPropertyValue)
A slightly more expensive workaround but 100% safe is to start all the values of your custom properties with a character that you then always strip off. When accessing the value, systematically remove the first character:
Dim MyProperty As Excel.CustomProperty = ...
Dim PropertyValue As String = Strings.Mid(MyProperty.Value, 2)
You can write an extension to make your life easier:
<System.Runtime.CompilerServices.Extension>
Function ValueTrim(MyProperty as Excel.CustomProperty) As String
Return Strings.Mid(MyProperty.Value, 2)
End Function
Now you can use it like this: Dim MyValue As String = MyProperty.ValueTrim
Use a reversed principle when you add a custom property:
<System.Runtime.CompilerServices.Extension>
Function AddTrim(MyProperties As Excel.CustomProperties, Name As String, Value As String) as Excel.CustomProperty
Dim ModifiedValue As String = String.Concat("~", Value) 'Use ~ or whatever character you lie / Note Strig.Concat is the least expensive way to join two strings together.
Dim NewProperty As Excel.CustomProperty = MyProperties.Add(Name, ModifiedValue)
Return NewProperty
End Function
To use like this: MyProperties.AddTrim(Name, Value)
Hope this helps other people who come across the issue..
Based on the other answers and some trial and error, I wrote a class to wrap a Worksheet.CustomProperty.
WorksheetProperty:Class
Sets and Gets the value of a Worksheet.CustomProperty and tests if a Worksheet has the CustomProperty
VERSION 1.0 CLASS
Attribute VB_Name = "WorksheetProperty"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
'#Folder("Classes")
'#PredeclaredId
Option Explicit
Private Type TMembers
Name As String
Worksheet As Worksheet
End Type
Private this As TMembers
Public Property Get Create(pWorksheet As Worksheet, pName As String) As WorksheetProperty
With New WorksheetProperty
Set .Worksheet = pWorksheet
.Name = pName
Set Create = .Self
End With
End Property
Public Property Get Self() As WorksheetProperty
Set Self = Me
End Property
Public Property Get Worksheet() As Worksheet
Set Worksheet = this.Worksheet
End Property
Public Property Set Worksheet(ByVal pValue As Worksheet)
Set this.Worksheet = pValue
End Property
Public Property Get Name() As String
Name = this.Name
End Property
Public Property Let Name(ByVal pValue As String)
this.Name = pValue
End Property
Public Property Get Value() As String
Dim P As CustomProperty
For Each P In Worksheet.CustomProperties
If P.Name = Name Then
Value = P.Value
Exit Property
End If
Next
End Property
Public Property Let Value(ByVal pValue As String)
Delete
Worksheet.CustomProperties.Add Name:=Name, Value:=pValue
End Property
Public Property Get hasCustomProperty(pWorksheet As Worksheet, pName As String) As Boolean
Dim P As CustomProperty
For Each P In pWorksheet.CustomProperties
If P.Name = pName Then
hasCustomProperty = True
Exit Property
End If
Next
End Property
Public Sub Delete()
Dim P As CustomProperty
For Each P In Worksheet.CustomProperties
If P.Name = Name Then
P.Delete
Exit For
End If
Next
End Sub
Usage
I have several properties of my custom Unit class return a WorksheetProperty. It makes it really easy to sync my database with my worksheets.
Public Function hasMeta(Ws As Worksheet) As Boolean
hasMeta = WorksheetProperty.hasCustomProperty(Ws, MetaName)
End Function
Public Property Get Id() As WorksheetProperty
Set Id = WorksheetProperty.Create(this.Worksheet, "id")
End Property
Public Property Get CourseID() As WorksheetProperty
Set CourseID = WorksheetProperty.Create(this.Worksheet, "course_id")
End Property
Public Property Get Name() As WorksheetProperty
Set Name = WorksheetProperty.Create(this.Worksheet, "unit_name")
End Property
Simple Usage
'ActiveSheet has a CustomProperty
Debug.Print WorksheetProperty.hasCustomProperty(ActiveSheet, "LastDateSynced")
'Set a CustomProperty
WorksheetProperty.Create(ActiveSheet, "LastDateSynced").Value = Now
'Retrieve a CustomProperty
Debug.Print WorksheetProperty.Create(ActiveSheet, "LastDateSynced").Value

Error says x is not a member of y, but it is

I have a sp that I added to my linq designer, which generated the result class:
Partial Public Class web_GetTweetsByUserIDResult
Private _userid As Integer
Private _tweetid As Integer
Private _TweeterFeed As String
Public Sub New()
MyBase.New
End Sub
<Global.System.Data.Linq.Mapping.ColumnAttribute(Storage:="_userid", DbType:="Int NOT NULL")> _
Public Property userid() As Integer
Get
Return Me._userid
End Get
Set
If ((Me._userid = value) _
= false) Then
Me._userid = value
End If
End Set
End Property
<Global.System.Data.Linq.Mapping.ColumnAttribute(Storage:="_tweetid", DbType:="Int NOT NULL")> _
Public Property tweetid() As Integer
Get
Return Me._tweetid
End Get
Set
If ((Me._tweetid = value) _
= false) Then
Me._tweetid = value
End If
End Set
End Property
<Global.System.Data.Linq.Mapping.ColumnAttribute(Storage:="_TweeterFeed", DbType:="NVarChar(100)")> _
Public Property TweeterFeed() As String
Get
Return Me._TweeterFeed
End Get
Set
If (String.Equals(Me._TweeterFeed, value) = false) Then
Me._TweeterFeed = value
End If
End Set
End Property
End Class
However, in this one section of code where I am trying to use the "TweeterFeed" member of the result class I am getting the error, "Error 4 'TweeterFeed' is not a member of 'System.Data.Linq.ISingleResult(Of web_GetTweetsByUserIDResult)'."
My code in this section is, :
<WebMethod()> _
Public Function GetTweetsByUserID(ByVal userID As Integer) As List(Of SimpleTweet)
Dim result As New List(Of SimpleTweet)
Dim urlTwitter As String = "https://api.twitter.com/1/statuses/user_timeline.xml?include_entities=true&include_rts=true&screen_name={0}&count=20"
Dim lq As New lqDFDataContext
Dim var = lq.web_GetTweetsByUserID(userID).ToList()
If Not var Is Nothing Then
For Each twitterfeed In var
Dim listURL As String = String.Format(urlTwitter, var.TweeterFeed)
Dim tweetXML As XmlDocument = utils.GetXMLForURL(listURL)
Dim tweetnodelist As XmlNodeList = tweetXML.ChildNodes(1).ChildNodes
For Each node As XmlNode In tweetnodelist
Dim tweet As New SimpleTweet
tweet.CreatedAt = node.SelectSingleNode("created_at").InnerText
tweet.HTMLText = utils.ReturnTextWithHRefLink(node.SelectSingleNode("text").InnerText)
tweet.ID = node.SelectSingleNode("id").InnerText
tweet.Name = node.SelectSingleNode("user/name").InnerText
tweet.ScreenName = node.SelectSingleNode("user/screen_name").InnerText
tweet.Text = node.SelectSingleNode("text").InnerText
tweet.UserID = node.SelectSingleNode("user/id").InnerText
tweet.ProfileImageURL = node.SelectSingleNode("user/profile_image_url_https").InnerText
result.Add(tweet)
Next
Next
End If
Return result
End Function
Does anyone have any idea what is going on? As far as I see "TweeterFeed" is clearly a member of the class, I can't figure out why I would be getting this error.
You're using var.TweeterFeed when you should be using twitterFeed.TweeterFeed. twitterFeed is a result extracted from var which is a sequence of results.
Using a more descriptive variable name than var would probably have made this clearer to you :)
I have this class
Public Class Tamano
Private pWidth As Integer
Private pHeight As Integer
Public Property Width As Integer
Public Property Height As Integer
End Class
I got the compilation error message 'Height' is not a member of 'Tamaño' in IIS
To fix it, add Set and Get to the properties and it compiles.
Public Class Tamano
Private pWidth As Integer
Private pHeight As Integer
Public Property Width As Integer
Get
Return pWidth
End Get
Set(value As Integer)
pWidth = value
End Set
End Property
Public Property Height As Integer
Get
Return pHeight
End Get
Set(value As Integer)
pHeight = value
End Set
End Property
End Class
This might not be directly related to your question but It might help someone else.