Tracking Controls via an Array - vb.net

so I have an array that holds picture boxes. Can someone help me in coding a much, much more efficient way in assigning each index? I just can't figure it out.
ArrayBullets(0) = picBullet0
ArrayBullets(1) = picBullet1
ArrayBullets(2) = picBullet2
ArrayBullets(3) = picBullet3
ArrayBullets(4) = picBullet4
ArrayBullets(5) = picBullet5
ArrayBullets(6) = picBullet6
ArrayBullets(7) = picBullet7
ArrayBullets(8) = picBullet8
ArrayBullets(9) = picBullet9
ArrayBullets(10) = picBullet10
ArrayBullets(11) = picBullet11
ArrayBullets(12) = picBullet12
ArrayBullets(13) = picBullet13
ArrayBullets(14) = picBullet14
ArrayBullets(15) = picBullet15
ArrayBullets(16) = picBullet16
ArrayBullets(17) = picBullet17
ArrayBullets(18) = picBullet18
ArrayBullets(19) = picBullet19
ArrayBullets(20) = picBullet20
ArrayBullets(21) = picBullet21
ArrayBullets(22) = picBullet22
ArrayBullets(23) = picBullet23
ArrayBullets(24) = picBullet24
ArrayBullets(25) = picBullet25
ArrayBullets(26) = picBullet26
ArrayBullets(27) = picBullet27
ArrayBullets(28) = picBullet28
ArrayBullets(29) = picBullet29
It would be much appreciated.

There is generally no reason at all to do this. They can always be found in the Controls Collection (you will not find them among Components). Though it looks ordered, your list is actually a bit arbitrary; they will always be in the Controls Collection in ZOrder which starts as the order added to the Designer and may or may not matter.
If you need a way to track them, rather than storing a reference, you can use a List(Of String) to store their names to use to reference them in the controls collection. If a control reference is somehow important, then a List(Of PictureBox) could be used instead.
Private myPicBoxes As New List(of String)
Method One - add names in Form Load:
For n As Integer = 0 To 29
myPicBoxes.Add(String.Format("picBullet{0}", n.ToString))
Next n
Method Two - get names from controls in Form Load
For Each pb As PictureBox In Me.Controls.OfType(Of PictureBox)
mypicBoxes.Add(pb.Name)
Next
To do something with a particular PB:
Me.Controls( myPicBoxes( mypicBoxes(theIndex) ) ).Image = FileName
Clear all images:
For Each pbName As String in myPicBoxes
Me.Controls(pbName).Image = Nothing
Next
' or
For n As Integer = 0 To myPicBoxes.Count - 1
Me.Controls(myPicBoxes(n)).Image = Nothing
Next n
If they are dynamic (you remove or add PictureBoxes at runtime) add/remove to your List as well:
Dim pb As New PictureBox
... set props
pb.Name = whatever you want
myPicBoxes.Add(pb.Name)
Me.Controls.Add(pb)
Removing:
Me.Controls.Remove( mypicBoxes(n))
mypicBoxes.RemoveAt(n) ' also remove the name from your tracker

If you're using the form designer designer to create your UI, populating the array manually really is the simplest and probably the best option.
You could iterate over Controls to find all the PictureBoxes and put them into an array; but that won't have a guaranteed sort order because the designer loves to rearrange its code every times you change something.

Related

Iterate through variables using a variable?

I'm trying to find a way to iterate through a list of Strings to be displayed in a text box. These Strings are retrieved from a separate class called 'texts'.
The Strings are declared in the 'texts' class as (for ngs1, 2, 3, etc)
Public Shared ngs1 As String = "Text"
This chunk runs when a next button is clicked, the button's purpose being to iterate through the list of texts displayed.
ElseIf firstTimeRun = True Then
welcome += 1
Select Case welcomePages
Case 1
txtDisplay.Text = texts.ngs1
Case 2
txtDisplay.Text = texts.ngs2
Case 3
txtDisplay.Text = texts.ngs3
End Select
I'm wanting to be able to do this without a select case, so that it's essentially
'Pseudo code
ElseIf firstTimeRun = True Then
welcome += 1
txtDisplay.text = texts.ngs(welcome)
I'm not sure how to properly do this, by using a variable in the name of other variables. Any help would be greatly appreciated, thanks!
If you just want to iterate through all this texts, just create a list(of String) or array and add all the ngsX...
As Example:
Dim list as List(Of String)
Dim indexActualShownString as Integer
Then you can just use in your Clicked_Event
txtDisplay.text=list.Items(indexActualShownString) as Integer
indexActualShwonString += 1
But I am not sure if I understand your problem right. And you should also implement a way to reset indexActualShownString, since I dont know what exactly its the purpose of it.

How to use reflection for accessing object from its name as a string

Ive a folder monitoring application where around 25 filewatchers monitoring 25 folders. Each of the filewatchers named fsw1,fsw2 ....
bCreateFileCheck = True
fsw1 = New FileSystemWatcher(My.Settings.UserRootFolder1)
fsw1.IncludeSubdirectories = True
fsw1.EnableRaisingEvents = True
fsw1.NotifyFilter = (NotifyFilters.LastAccess Or NotifyFilters.LastWrite Or NotifyFilters.FileName)
So this is repeating for the 25 folders, but only difference is name changing of fsw1 to fsw2,fsw3 etc. and also My.Settings.UserRootFolder1 to My.Settings.UserRootFolder2,My.Settings.UserRootFolder3 etc.
So how can we achieve this using for loop without writing individual code blocks for every filewatchers. I guess using some reflection techniques it can be achieved.
Don't make your life harder than it needed to be. Use an array (or List(Of T) if you need something flexible):
Dim watchers(24) As FileSystemWatcher
For i As Integer = 0 To watchers.GetUpperBound(0)
Dim path = CStr(My.Settings.Item("UserRootFolder" & (i + 1)))
watchers(i) = New FileSystemWatcher(path)
'Do further initialization...
Next
If the structure is fixed and you cannot really change it, you can set the variables to the objects that you created in the For loop. So change the loop as follows:
'...
Dim watcher = New FileSystemWatcher(...)
Me.GetType().GetField("fsw" & (i + 1)).SetValue(Me, watcher)
This gets the field with the appropriate name and sets its value to the object that you just created (I assume that it is a field based on its naming).

Refer to forms controls using variable

I've seen many threads on this, but I'm pretty much lost.
For the example below, I have 3 ComboBoxes (cbx_example0, cbx_example1, cbx_example2) located on three TabPages (index 0, 1, 2), respectively. I'd like set the value of the variable myVariable based on the ComboBox on the selected TabPage.
However, I can't seem to figure out how to refer to the ComboBox using a variable. It seems like it should be straightforward, but I guess not. No matter what I do, I get a NullReferenceException.
Function to get TabPage Index number (returns 0 for this example)
Function getTabIndex()
Dim currentTabIndex As Int32 = frm_Main.TabControl1.SelectedIndex
Return currentTabIndex
End Function
Attempt 1 to refer to ComboBox with variable
Dim myVariable As String
Dim i As Integer = getTabIndex
myVariable = frm_Main.Controls("cbx_example" & i).Text
Attempt 2 to refer to ComboBox with variable
Dim cbx_example0 As New ComboBox
Dim i As Integer = getTabIndex()
Dim name As String = "cbx_example" & i.ToString
cbx_example = frm_Main.Controls.Item(name)
myVariable = cbx_example.Text
Your problem is that you think that your cbo is located on the form, while in reality it is on the tabpage. Instead of
cbx_example = frm_Main.Controls.Item(name)
use (for example)
cbx_example = frm_Main.TabPage1.Controls.Item(name)
Keep in mind that your combo is probably not on tab itself but on the tabpage
On another note, I see no need for getTabIndex(). And another way to get any control within hierarchy of your form is to use
form.Controls.Find(key, searchAllChildren)

VB.NET Array/Hashtable Issue

I am trying to make an array of hashtables. I don't know if this is the best solution, in PHP I would just do a multi-dim array, but it's not so easy in .NET. I am pretty new o VB, so if there is a better solution for this please explain.
I have 2 emails fields for a contact, and a contact can have many. I just want to load in the first two on the edit page for editing, whatever they may be.
Private Sub loadPrimaryContactEmails(ByVal db As CRMDataDataContext, ByVal contactID As Guid)
Dim q = (From ce In db.ContactEmails Where ce.ContactID = contactID Select ce).Take(2)
Dim Emails As Array
Dim count = 0
For Each email In q
Emails(count) = New Hashtable
Emails(count).Add("email", email.Email)
Emails(count).Add("label", email.Label)
Emails(count).Add("id", email.ContactEmailID)
count = count + 1
Next
txtPCEmail1.Text = Emails(0).Item("email")
txtPCEmail1Label.Text = Emails(0).Item("label")
lblEmail1ID.Text = Emails(0).Item("id")
txtPCEmail2.Text = Emails(1).Item("email")
txtPCEmail2Label.Text = Emails(1).Item("label")
lblEmail2ID.Text = Emails(1).Item("id")
End Sub
I get the error the first time I try to reference my array:
txtPCEmail1.Text = Emails(0).Item("email")
The error is:
Object variable or With block variable not set.
It builds, so I thought it might work. I can't just loop through my datasource because I have to explicitly set textbox fields. Is there a better way to go about doing this? Or is there a way to make an array of hashtables work?
EDIT - here is the good code:
So I went w/ the HybridDictionary...
Private Sub loadPrimaryContactEmails(ByVal db As CRMDataDataContext, ByVal contactID As Guid)
Dim q = (From ce In db.ContactEmails Where ce.ContactID = contactID Select ce).Take(2)
Dim Emails As New HybridDictionary()
Dim count = 1
For Each email In q
Emails.Add("email" + NCStr(count), email.Email)
Emails.Add("label" + NCStr(count), email.Label)
Emails.Add("id" + NCStr(count), email.ContactEmailID)
count = count + 1
Next
txtPCEmail1.Text = Emails("email1")
txtPCEmail1Label.Text = Emails("label1")
lblEmail1ID.Text = Emails("id1")
txtPCEmail2.Text = Emails("email2")
txtPCEmail2Label.Text = Emails("label2")
lblEmail2ID.Text = Emails("id2")
End Sub
SO yeah, kind of a hack, but I don't feel like I should have to making special methods just to load some data into a dictionary or array or whatever.
Arrays in VB.NET are different than in PHP. You will need to define the size of your array before attempting to set elements of the array.
Better yet, consider using the generic List<T> collection.
Yes Phil is right you haven't specified the Initial Size of the Array.
And as suggested by him Use generic list or I would recommend
"System.Collections.Specialized.StringCollection" Class or "System.Collections.Specialized.HybridDictionary" class
Build the hashtable first and then build the array.
Dim hash As New Hashtable()
hash.Add("Header", shortModel)
hash.Add("SpecInfo", specinfo)
hash.Add("SerialNumber", serie & "-L")
hash.Add("SerialNumber2", serie)
hash.Add("seriel", serie & "-L")
hash.Add("serie", serie)
hash.Add("Product", modelBase)
hash.Add("varBC", bc)
hash.Add("box_id", boxId.Substring(4).ToString)
Dim dt As DataTable = DbUtil.GetCursor("SFISM4.PKG_AGENCY.sp_get_print_param", {New OracleParameter("in_serie", "3CE5151ZW4")})
For Each row As DataRow In dt.Rows
hash.Add(row("NAME"), row("VALUE"))
Next
Dim mArray(hash.Count() - 1, 1) As String
Dim i As Integer = 0
For Each row As DictionaryEntry In hash
mArray(i, 0) = row.Key.ToString()
mArray(i, 1) = row.Value.ToString()
i = i + 1
Next

Update columns in one LINQ object with another LINQ object

I have two LINQ objects which have exactly the same columns and I would like to be able to update one with the fields from the other. I first create a new object from some data in a file, then I query the database for an existing item with the same ID. What I would like to be able to do is update the existing objects details with the newly created objects details.
So far the way I have been doing it is to list all the columns and update them manually but as you can see this can cause maintenance headaches.
With OldCaller
.ADDRESS = NewCaller.ADDRESS
.COMPANY = NewCaller.COMPANY
.CONTACT_HOURS = NewCaller.CONTACT_HOURS
.CONTACT_NAME = NewCaller.CONTACT_NAME
.CUSTOMER_ID = NewCaller.CUSTOMER_ID
.EMAIL_ADDRESS = NewCaller.EMAIL_ADDRESS
.FAX_NUMBER = NewCaller.FAX_NUMBER
.FAX_TYPE = NewCaller.FAX_TYPE
.MOBILE = NewCaller.MOBILE
.POSTCODE = NewCaller.POSTCODE
.PUBLIC_ADDRESS = NewCaller.PUBLIC_ADDRESS
.PUBLIC_TELEPHONE = NewCaller.PUBLIC_TELEPHONE
.STATE = NewCaller.STATE
.SUBURB = NewCaller.SUBURB
.TELEPHONE = NewCaller.TELEPHONE
End With
I would like to be able to find a way to clean this up a bit. Does anyone know of a better way to do what I need.
I do this sort of thing when I create an instance of an object from a template. Basically I have a method that iterates over the public properties of the template, finds the corresponding property in the object being created, and invokes the property setter on the new object, all via reflection.
I haven't tested this yet but this is what I have come up with.
Dim _OldCallerProperties = OldCaller.GetType().GetProperties(Reflection.BindingFlags.Public)
Dim _NewCallerProperties = NewCaller.GetType.GetProperties(Reflection.BindingFlags.Public)
For Each Prop In _OldCallerProperties
Dim _matchingProperty = _NewCallerProperties.Where(Function(p) p.Name = Prop.Name).FirstOrDefault
Dim _newvalue = _matchingProperty.GetValue(_matchingProperty, Nothing)
Prop.SetValue(Prop, _newvalue, Nothing)
Next
Like I said I haven't tested it but I'm sure it should work.