Creating a complex structure with Scripting Dictionary - VBScript - scripting

I am trying to understand some code so that i can make modifications to it. I am fairly new at vbscript so any help is appreciated .
I am looking at a Dictionary object that looks like it is behaving like a table with different rows controlled by a key. I am not sure what is happening. commands like
list.add list.count+1 , ListElement are a little over my league right now. The code is able to output data for 1 use with simple statement
Sub DumpList ( list )
' This function dumps all the people in the office and their information
' in the application window. The list is usually sorted by Name.
Dim e, le
For Each e In list ' output listelements...
Set le = list(e)
LogOutput 0, "line: " & (le.num, 3) & " : " & le.Name _
& " " & le.PHNumber1 & " " & le.PHNumber2 _
& " " & le.Email1 & " " & le.Email2 _
& " " & le.DeskNo.1 & " " & le.OFficeCode _
& " " & le.wirecolour & " " & le.wirecross
Next
End Sub
I am not sure how it is working for me to make any changes to it.
Thanks again

The task:
Maintain a collection of persons.
First attempt at a solution:
Use a dictionary with numerical indices=keys, based on dic.Count
As sanwar pointed out, a dictionary stores key-value pairs. To put (info about)
persons in a dictionary, we need a person class from which we can create person
objects/instances to hold the multiple information elements.
Minimal/POC code for a Person class:
Dim g_nPersonId : g_nPersonId = -1
Class cPerson
Private m_nId
Private m_sName
Private m_dtBirth
Private m_dWage
Public Function init( sName, dtBirth, dWage )
Set init = Me
g_nPersonId = g_nPersonId + 1
m_nId = g_nPersonId
Name = sName
Birth = dtBirth
Wage = dWage
End Function
Public Property Let Name( sName ) : m_sName = sName : End Property
Public Property Let Birth( dtBirth ) : m_dtBirth = dtBirth : End Property
Public Property Let Wage( dWage ) : m_dWage = dWage : End Property
Public Property Get Id() : Id = m_nId : End Property
Public Property Get Name() : Name = m_sName : End Property
Public Property Get Birth() : m_dtBirth = m_dtBirth : End Property
Public Property Get Wage() : m_dWage = m_dWage : End Property
Public Function Data()
Data = Array( m_nId, m_sName, m_dtBirth, m_dWage )
End Function
End Class ' cPerson
[The class cPerson defines/blue prints persons, each having an id, a name, a dob, and
a salary. You create persons by calling the init function passing suitable values
for name, doc, and wage members; the id will augmented automagically (by using a global
counter instead of proper class level data as possible in more capable OO languages).]
and a demo script to prove we can create and display persons:
Dim oAdam : Set oAdam = New cPerson.init( "Adam", #1/5/2001#, 1234.56 )
Dim oEve : Set oEve = New cPerson.init( "Eve" , #1/6/2001#, 6543.21 )
Dim oPerson
For Each oPerson In Array( oAdam, oEve )
WScript.Echo Join( oPerson.Data(), " - " )
Next
output:
0 - Adam - 1/5/2001 - 1234.56
1 - Eve - 1/6/2001 - 6543.21
Now lets put them in a dictionary with numerical keys (a VBScript special
feature, other languages have string-key-only dictionaries) based on the
.Count property. The .Count property of an empty dictionary is 0, by adding
the first element (a person object holding all info we need) to the dictionary
its .Count increments to 1 (ready for the next addition). You easily can see
that .Add .Count + 1 is a waste of time/effort:
Dim dicPersons : Set dicPersons = CreateObject( "Scripting.Dictionary" )
Dim aPersons : aPersons = Array( _
Array( "Adam", #1/5/2001#, 1234.56 ) _
, Array( "Eve" , #1/6/2001#, 6543.21 ) _
)
Dim aPerson
For Each aPerson In aPersons
dicPersons.Add dicPersons.Count, New cPerson.init( aPerson( 0 ), aPerson( 1 ), aPerson( 2 ) )
Next
Dim nPerson
WScript.Echo "Adam & Eve"
For Each nPerson In dicPersons
WScript.Echo nPerson, ":", Join( dicPersons( nPerson ).Data(), " - " )
Next
dicPersons.Remove 0 ' how do we know the key of Adam?
WScript.Echo "Adam zaped"
For Each nPerson In dicPersons
WScript.Echo nPerson, ":", Join( dicPersons( nPerson ).Data(), " - " )
Next
WScript.Echo "Trying to add Caine"
On Error Resume Next
dicPersons.Add dicPersons.Count, New cPerson.init( "Caine", Date(), 0.33 )
WScript.Echo Err.Description
On Error GoTo 0
The output
Adam & Eve
0 : 0 - Adam - 1/5/2001 - 1234.56
1 : 1 - Eve - 1/6/2001 - 6543.21
Adam zaped
1 : 1 - Eve - 1/6/2001 - 6543.21
Trying to add Caine
This key is already associated with an element of this collection
shows why dictionaries with numerical indices based on .Count are no solution
for the task: Maintain a collection of persons.

In this case the variable list holds a Scripting.Dictionary.
When you use the VBScript For Each construct on Scripting.Dictionary each key in the dictionary is returned. So in this case the For Each will loop place each key in the variable e on each iteration.
The Line:-
Set le = list(e)
is now using the key for this loop to lookup the value in the dictionary associated with the key. In this case the value is an object that has properties.
Hence a dictionary can be used to quickly and directly lookup a "row" in a "table" using its key. Also as the code you've posted demonstrates you can enumerate each key and lookup each value to "scan" the whole "table".

Related

How do I assign an already known integer to a field after the NotInList event is called?

I have this complicated VBA function on a MSAccess form frm_DataEntry. It searches for values which are not in a list. The function is called on de NotInList event of the comboboxes.
When the typed string in combobox cbo_CustomerLocations is not in the list, it will ask if I want to add it to the table tbl_CustomerLocations by Yes/No question. After that it goes from 1st column to the last column and asks if I want to add some new data. The code below shows how to add a CustomerLocation.
The last field CustomerID of my table tbl_CustomerLocations is linked to the CustomerID field of table tbl_Customers
Now my question:
How do I alter my VBA code when the NotInList event is called, and when it reaches the CustomerID column (the last column), It must not ask 'What do you want for CustomerID', but rather automatically selects the CustomerID I previously selected on the same form frm_DataEntry on combobox cbo_Customers?
Private Sub cbo_CustomerLocationID_NotInList(NewData As String, Response As Integer)
Dim oRS As DAO.Recordset, i As Integer, sMsg As String
Dim oRSClone As DAO.Recordset
Response = acDataErrContinue
String_Value = Me.cbo_CustomerLocationID.Text
MsgBold = String_Value
MsgNormal = "Add to list with locations?"
Debug.Print
If Eval("MsgBox ('" & MsgBold & vbNewLine _
& "#" & MsgNormal & "##', " & vbYesNo & ", 'New Location')") = vbYes Then
Set oRS = CurrentDb.OpenRecordset("tbl_CustomerLocations", dbOpenDynaset)
oRS.AddNew
oRS.Fields(1) = NewData
For i = 2 To oRS.Fields.Count - 1
sMsg = "What do you want for " & oRS(i).Name
oRS(i).Value = InputBox(sMsg, , oRS(i).DefaultValue)
Next i
oRS.Update
cbo_CustomerLocationID = Null
cbo_CustomerLocationID.Requery
DoCmd.OpenTable "tbl_CustomerLocations", acViewNormal, acReadOnly
Me.cbo_CustomerLocationID.Text = String_Value
End If
End Sub
Use an If Then block within the loop to check for name of field.
If oRS(i).Name = "CustomerID" Then
oRS(i) = Me.cbo_Customers
Else
sMsg = "What do you want for " & oRS(i).Name
oRS(i).Value = InputBox(sMsg, , oRS(i).DefaultValue)
End If

Type mismatch error using custom class subroutine in Excel VBA

Working in Excel VBA, I have a class module where I define my class 'Marker'. One of the properties of my class is TextLine(), which is an array that holds up to 5 strings. I have defined the two methods below in my class module. In another (regular) module, I fill markerArr() with my custom Marker objects. Loading each object's properties with data at each array index is working fine... However, after loading data into the object at each index, I try to use markerArr(count).ProcessLines but receive a type mismatch error. Since ProcessLines is a public sub in my class module, and markerArr(count) contains a Marker object, I can't seem to understand why this error is occurring... Am I overlooking something obvious?
'Serial number replacement processing function
Public Sub ProcessLines()
Dim strSerial As String
Dim toggle As Boolean
toggle = False
Dim i As Integer
For i = 0 To 4
If Trim(m_TxtLines(i)) <> "" Then
'Add linefeed char to non-empty text lines
m_TxtLines(i) = m_TxtLines(i) & Chr(10)
'Detect if it is a serialized line
If InStr(1, m_TxtLines(i), "XXXXXX-YYY") > 0 Then
m_Serial(i) = True
toggle = True
End If
End If
Next
'When at least one line on the marker is serialized, create and replace serial text
If toggle = True Then
'Only prompt for input once
If startSerNo < 1 And Num_Sers < 1 Then
startSerNo = InputBox("Enter the serial number to start printing at." & Chr(10) & _
"Entering 1 will result in -001, entering 12 will result in -012, etc.", "Starting Serial #", "1")
Num_Sers = InputBox("Enter the amount of serializations to perform." & Chr(10) & _
"This will control how many copies of the entire marker set are printed.", "Total Serializations", "1")
End If
strSerial = CreateSerial(startSerNo)
Dim j As Integer
For j = 0 To 4
If m_Serial(j) Then
m_TxtLines(j) = Replace(m_TxtLines(j), "XXXXXX-YYY", strSerial)
End If
Next
End If
End Sub
'Creates the string to replace XXXXXX-YYY by concatenating the SFC# with the starting serial number
Private Function CreateSerial(ByVal startNum As Integer)
Dim temp
temp = SFC_Num
Select Case Len(CStr(startNum))
Case 1
temp = temp & "-00" & startNum
Case 2
temp = temp & "-0" & startNum
Case 3
temp = temp & "-" & startNum
Case Else
temp = temp & "-001"
End Select
CreateSerial = temp
End Function
Your CreateSerial function takes an integer as a parameter, but you are attempting to pass a string. I've pointed out some problems:
If startSerNo < 1 And Num_Sers < 1 Then 'Here I assume, you have these semi-globals as a variant - you are using numeric comparison here
startSerNo = InputBox("Enter the serial number to start printing at." & Chr(10) & _
"Entering 1 will result in -001, entering 12 will result in -012, etc.", "Starting Serial #", "1") 'Here startSerNo is returned as a string from the inputbox
Num_Sers = InputBox("Enter the amount of serializations to perform." & Chr(10) & _
"This will control how many copies of the entire marker set are printed.", "Total Serializations", "1") 'here Num_Sers becomes a String too
End If
strSerial = CreateSerial(startSerNo) 'here you are passing a String to the CreateSerial function. Either pass an integer, or allow a variant as parameter to CreateSerial
'......more code.....
Private Function CreateSerial(ByVal startNum As Integer)

Loop through class properties?

I have a class ("Names"):
Option Explicit
Public companyName As String
Public companyCode As String
Public companyCountry As String
Property Get fullInfo() As String
fullInfo = "Code " & companyCode & " is " & companyCountry & " for " & companyName
End Property
and in a Sub() in a Module, I have the following:
Sub classTest()
Dim c1 As New Names
Dim c2 As New Names
c1.companyCode = 14
c1.companyCountry = "Ivory Coast"
c1.companyName = "Ivory Company"
c2.companyCode = 11
c2.companyCountry = "Cameroon"
c2.companyName = "Cameroon Company"
Dim i As Integer
debug.print c1.fullInfo
End Sub
This correctly will print "Code 14 is Ivory Coast for Ivory Company".
How can I write a loop to go through ALL the properties (is that the right word? is c1, c2, a 'property'?). I tried something like below, but it didn't work:
for i = 1 to 2
debug.print ci.fullInfo
next i
You can see that it obviously won't work - but how can I get it to do so? Sorry, I don't know what the c1 part is called, nor what's the part after the . is called)
If you store c1,c2,etc in an array or collection then you can loop over them using a standard For loop and call fullInfo for each of them.
Sub Tester()
Dim col As New Collection, n As Names, i
For i = 1 To 10
Set n = New Names
n.companyCode = i
n.companyCountry = "Country_" & i
n.companyName = "Company_" & i
col.Add n
Next i
For Each n In col
Debug.Print n.fullInfo
Next n
End Sub
Look at a for each loop. Something like
For Each variable_name In collection_name
'Some code here.
Next variable_name

How to Update child class when parent class changes in Enterprise Architect

I want to make a class diagram in Enterprise Architect ( Version 10.0 ) which implement an inheritance. I add an abstract class then create 3 class which implement abstract class.
Now if I make some change in abstract class, child classes doesn't change. (for example add another method to abstract class, but child class dose not have this method).
How can update(or refresh) a child class when parent class changed?
Select the class and press Ctrl + Shift + o to refresh. However this doesn't perform full refresh, so you will need to remove older versions of operations etc, but EA will display the override methods dialog.
You can use my addin EA-Matic to do so.
EA-Matic catches the add-in events in Enterprise Architect and forwards them the built-in scripting environment.
This allows to create scripts with full blown add-in abilities, synchronizing overrides is just one of the possible applications.
One of the example scripts I wrote to demonstrate the add-in does exactly this: Automatically synchronize overrides in Enterprise Architect with EA-Matic
This example script uses the events EA_OnContextItemChanged to store the overrides of the selected operation
'Event Called when a new element is selected in the context. We use this operation to keep the id of the selected operation and a list of its overrides
'Because now is the only moment we are able to find it's overrides. Once changed we cannot find the overrides anymore because then they already
'have a different signature
function EA_OnContextItemChanged(GUID, ot)
'we only want to do something when the selected element is an operation
if ot = otMethod then
'get the model
dim model
set model = getEAAddingFrameworkModel()
'get the operation
dim operation
set operation = model.getOperationByGUID(GUID)
'remember the operationID
operationID = operation.id
'remember the overrides
set overrides = getOverrides(operation, model)
Repository.WriteOutput "EA-Matic", overrides.Count & " overrides found for: " & operation.name,0
end if
end function
and EA_OnNotifyContextItemModified to modify the overrides in case something changed.
'Event called when an element is changed. Unfortunately EA doesn't call it for an operation, only for the owner so we have to work with that.
function EA_OnNotifyContextItemModified(GUID, ot)
'we only want to do something when the selected element is an operation
if ot = otElement then
'get the operation
'Here we use the EA API object directly as most set methods are not implemented in EA Addin Framework
dim wrappedOperation
set wrappedOperation = Repository.GetMethodByID(operationID)
dim modifiedElement
set modifiedElement = Repository.GetElementByGuid(GUID)
if not wrappedOperation is Nothing and not modifiedElement is Nothing then
'check to be sure we have the same operation
if modifiedElement.ElementID = wrappedOperation.ParentID AND overrides.Count > 0 then
dim synchronizeYes
synchronizeYes = MsgBox("Found " & overrides.Count & " override(s) for operation "& modifiedElement.Name & "." & wrappedOperation.Name & vbNewLine & "Synchronize?" _
,vbYesNo or vbQuestion or vbDefaultButton1, "Synchronize overrides?")
if synchronizeYes = vbYes then
synchronizeOverrides wrappedOperation
'log to output
Repository.WriteOutput "EA-Matic", "Operation: " & wrappedOperation.name &" synchronized" ,0
end if
'reset operationID to avoid doing it all again
operationID = 0
end if
end if
end if
end function
In OnContextItemChanged it gets the overrides by first selecting all operations with the same signature from the model with a query.
'gets the overrides of the given operation by first getting all operations with the same signature and then checking if they are owned by a descendant
function getOverrides(operation, model)
'first get all operations with the exact same signature
dim overrideQuery
overrideQuery = "select distinct op2.OperationID from (((t_operation op " & _
"inner join t_operation op2 on op2.[Name] = op.name) "& _
"left join t_operationparams opp on op.OperationID = opp.OperationID) "& _
"left join t_operationparams opp2 on opp2.OperationID = op2.OperationID) "& _
"where op.OperationID = "& operation.id &" "& _
"and op2.ea_guid <> op.ea_guid "& _
"and (op2.TYPE = op.Type OR (op2.TYPE is null AND op.Type is null)) "& _
"and (op2.Classifier = op.Classifier OR (op2.Classifier is null AND op.Classifier is null)) "& _
"and (opp.Name = opp2.Name OR (opp.Name is null AND opp2.Name is null)) "& _
"and (opp.TYPE = opp2.TYPE OR (opp.TYPE is null AND opp2.Type is null)) "& _
"and (opp.DEFAULT = opp2.DEFAULT OR (opp.DEFAULT is null AND opp2.DEFAULT is null)) "& _
"and (opp.Kind = opp2.Kind OR (opp.Kind is null AND opp2.Kind is null)) "& _
"and (opp.Classifier = opp2.Classifier OR (opp.Classifier is null AND opp2.Classifier is null)) "
dim candidateOverrides
set candidateOverrides = model.ToArrayList(model.getOperationsByQuery(overrideQuery))
'then get the descendants of the owner
dim descendants
dim descendant
'first find all elements that either inherit from the owner or realize it
dim owner
set owner = model.toObject(operation.owner)
set descendants = getDescendants(owner, model)
'then filter the candidates to only those of the descendants
'loop operations backwards
dim i
for i = candidateOverrides.Count -1 to 0 step -1
dim found
found = false
for each descendant in descendants
if descendant.id = model.toObject(candidateOverrides(i).owner).id then
'owner is a descendant, operation can stay
found = true
exit for
end if
next
'remove operation from non descendants
if not found then
candidateOverrides.RemoveAt(i)
end if
next
set getOverrides = candidateOverrides
end function
Then we its all the descendants of the owner of the operation (recursively) and filter the operations to only those owned by a descendant.
'gets all descendant of an element. That is all subclasses and classes that Realize the element.
'Works recursively to get them all.
function getDescendants(element, model)
dim descendants
dim getdescendantsQuery
getdescendantsQuery = "select c.Start_Object_ID as Object_ID from (t_object o " _
& "inner join t_connector c on c.End_Object_ID = o.Object_ID) " _
& "where "_
& "(c.[Connector_Type] like 'Generali_ation' "_
& "or c.[Connector_Type] like 'Reali_ation' )"_
& "and o.Object_ID = " & element.id
set descendants = model.toArrayList(model.getElementWrappersByQuery(getdescendantsQuery))
'get the descendants descendants as well
dim descendant
dim descendantsChildren
for each descendant in descendants
if IsEmpty(descendantsChildren) then
set descendantsChildren = getDescendants(descendant, model)
else
descendantsChildren.AddRange(getDescendants(descendant, model))
end if
next
'add the descendantsChildren to the descendants
if not IsEmpty(descendantsChildren) then
if descendantsChildren.Count > 0 then
descendants.AddRange(descendantsChildren)
end if
end if
set getDescendants = descendants
end function
Finally it synchronizes the operations using the following functions
'Synchronizes the operation with it's overrides
function synchronizeOverrides(wrappedOperation)
dim override
for each override in overrides
dim wrappedOverride
set wrappedOverride = override.WrappedOperation
'synchronize the operation with the override
synchronizeOperation wrappedOperation, wrappedOverride
'tell EA something might have changed
Repository.AdviseElementChange wrappedOverride.ParentID
next
end function
'Synchronizes the operation with the given override
function synchronizeOperation(wrappedOperation, wrappedOverride)
dim update
update = false
'check name
if wrappedOverride.Name <> wrappedOperation.Name then
wrappedOverride.Name = wrappedOperation.Name
update = true
end if
'check return type
if wrappedOverride.ReturnType <> wrappedOperation.ReturnType then
wrappedOverride.ReturnType = wrappedOperation.ReturnType
update = true
end if
'check return classifier
if wrappedOverride.ReturnType <> wrappedOperation.ReturnType then
wrappedOverride.ReturnType = wrappedOperation.ReturnType
update = true
end if
if update then
wrappedOverride.Update
end if
'check parameters
synchronizeParameters wrappedOperation, wrappedOverride
end function
'Synchronizes the parameters of the given operatin with that of the overrride
function synchronizeParameters(wrappedOperation, wrappedOverride)
'first make sure they both have the same number of parameters
if wrappedOverride.Parameters.Count < wrappedOperation.Parameters.Count then
'add parameters as required
dim i
for i = 0 to wrappedOperation.Parameters.Count - wrappedOverride.Parameters.Count -1
dim newParameter
set newParameter = wrappedOverride.Parameters.AddNew("parameter" & i,"")
newParameter.Update
next
wrappedOverride.Parameters.Refresh
elseif wrappedOverride.Parameters.Count > wrappedOperation.Parameters.Count then
'remove parameters as required
for i = wrappedOverride.Parameters.Count -1 to wrappedOperation.Parameters.Count step -1
wrappedOverride.Parameters.DeleteAt i,false
next
wrappedOverride.Parameters.Refresh
end if
'make parameters equal
dim wrappedParameter
dim overriddenParameter
dim j
for j = 0 to wrappedOperation.Parameters.Count -1
dim parameterUpdated
parameterUpdated = false
set wrappedParameter = wrappedOperation.Parameters.GetAt(j)
set overriddenParameter = wrappedOverride.Parameters.GetAt(j)
'name
if overriddenParameter.Name <> wrappedParameter.Name then
overriddenParameter.Name = wrappedParameter.Name
parameterUpdated = true
end if
'type
if overriddenParameter.Type <> wrappedParameter.Type then
overriddenParameter.Type = wrappedParameter.Type
parameterUpdated = true
end if
'default
if overriddenParameter.Default <> wrappedParameter.Default then
overriddenParameter.Default = wrappedParameter.Default
parameterUpdated = true
end if
'kind
if overriddenParameter.Kind <> wrappedParameter.Kind then
overriddenParameter.Kind = wrappedParameter.Kind
parameterUpdated = true
end if
'classifier
if overriddenParameter.ClassifierID <> wrappedParameter.ClassifierID then
overriddenParameter.ClassifierID = wrappedParameter.ClassifierID
parameterUpdated = true
end if
'update the parameter if it was changed
if parameterUpdated then
overriddenParameter.Update
end if
next
end function
When you tell EA to override or implement an operation in a base class or interface, it creates a copy of the operation in the child class. This copy has no reference to the original base class / interface, and subsequent changes are not reflected in the child.
If you draw a realization to an interface and select not to override any operations, EA will generate code for them as you'd expect, but it doesn't do that for abstract classes - even if the child is a leaf.
You can always modify the code generation templates (Tools - Source Code Generation Templates). They're a bit tricky to get your head around the first time, but you'll soon get the hang of it.

Only one textbox value entered appears in listbox

Simple beginners issue here, go easy. I've got a few text boxes that the user can put values into + pick a date, and I want them to appear in a list box. Unfortunately only the 2nd text box's value appears multiple times. This can be seen here: http://i.stack.imgur.com/kCqrz.png
Here is the full form code: http://pastebin.com/MDb1hSCA
Here's where the data is added to an array:
stockArray(nofDataDay, lowValue) = possibleLow
stockArray(nofDataDay, highValue) = possibleHigh
stockArray(nofDataDay, openValue) = possibleOpen
stockArray(nofDataDay, closeValue) = possibleClose
dateArray(nofDataDay) = Convert.ToDateTime(WeatherDateTimePicker.Text)
nofDataDay = nofDataDay + 1
And here's where it's displayed:
For day = 0 To nofDataDay - 1
StockListBox.Items.Add(dateArray(day).ToShortDateString & _
delimiter & stockArray(day, openValue).ToString & _
delimiter & stockArray(day, closeValue).ToString & _
delimiter & stockArray(day, highValue).ToString & _
delimiter & stockArray(day, lowValue).ToString & _
delimiter & AverageStock(stockArray(day, lowValue), stockArray(day, highValue)))
Next
For some reason, it's only adding the Close value.
You never set the value of your column index variables (viz. openValue, closeValue, highValue, lowValue). They all default to zero, so you are in just adding the first column multiple times. You could set the value of them when you declare them, like this:
Dim lowValue As Integer = 0
Dim highValue As Integer = 1
Dim openValue As Integer = 2
Dim closeValue As Integer = 3
You'll need to declare your array larger too:
Dim stockArray(30, 3) As Integer
However, by default Dim declares fields as public, and since that's probably not what you really want, I would recommend changing them to private. Also, the column indexes really ought to be constants:
Private Const lowValue As Integer = 0
Private Const highValue As Integer = 1
Private Const openValue As Integer = 2
Private Const closeValue As Integer = 3
Private stockArray(30, 3) As Integer
However, this kind of bug would not be possible you designed your code better. Rather than using a two-dimensional array, I would recommend making a class that stores all the data for a single item. Then, rather than an array, use a List(T) object to store the list of items. For instance:
Public Class MyItem
Public Date As Date
Public LowValue As Integer
Public HighValue As Integer
Public OpenValue As Integer
Public CloseValue As Integer
End Class
Private myItems As New List(Of MyItem)()
Then, you can add the items like this:
Dim item As New MyItem()
item.Date = Convert.ToDateTime(WeatherDateTimePicker.Text)
item.LowValue = possibleLow
item.HighValue = possibleHigh
' ...
myItems.Add(item)
And then you can read the items from the list like this:
For Each item As MyItem in myItems
StockListBox.Items.Add(item.Date.ToShortDateString() & _
delimiter & item.OpenValue.ToString() & _
delimiter & item.CloseValue.ToString() & _
delimiter & item.HighValue.ToString() & _
delimiter & item.LowValue.ToString() & _
delimiter & AverageStock(item.LowValue, item.HighValue))
Next
As you can see, doing it that way is much more self-documenting, less confusing, and less bug-prone.