Visual basic 2008 issue with adding a method to my dynamic objects - vb.net

I have searched for an answer to my question since last thursday. A lot of answers about my exact same question have been answerd in vb.net. However, I am working on Visual Basic 2008 and those two language seems to have differences that are for me difficult to understand. So here is my issue.
I need to create several picture box and I have created them dynamicly as several sites recommanded. That part works fine. Issue begins when I want to click on them. I read enough to understant that it is not because I have created the object that I have created the method attached to them. Then I create the method. Still no problem except when I am running the code each button does the same thing because they are all attached to the same method. I came to a solution: I need to transfer with the method an argument to tell wich Picturebox I am clicking on, but because I am using addressof I can't. I know few sites that have talked about the same issues and solved it using a lamda expression. If someone could give me the code I should use I would be really thankful.
Here is my code:
For i = 0 To 7
'couleur is the name I give to my picturebox object and objet () is the sub in which I created my object
couleur(i) = objet()
Next
For x = 0 To 7
' initiasation of location, etc.
Next
' This is the issue !!! I do not know how to say this line into vb8
' I want to pass in argument X to know on which object I have cliked on and then use a seled case to make separated command afterward.
For x = 0 To 7
AddHandler couleur(i).Click, Function(senderobj, args) couleur_click(x)
Next
End Sub
Sub couleur_click(ByVal i As Integer)
' select case doing seperated things depending on the x receive in argument
End Sub
Thank all of you for help, sorry for my language it is not my first language.

Why don't you change couleur_click to take the sender as a parameter? You will then know the source of the click, from which you can find the index of the PictureBox in your couleur array:
' ...
For x = 0 To 7
AddHandler couleur(i).Click, AddressOf couleur_click
Next
' ...
Sub couleur_click(sender As Object, e As EventArgs)
Dim pictureBoxSource As PictureBox = sender
' Find the index of the source in the base collection
Dim index = Array.IndexOf(couleur, pictureBoxSource)
Select Case index
' ...
End Select
End Sub

Set the tag property of each PictureBox, then in the click event handler you can do a select case on the tag.
You can't add parameters to the built in event handlers.

Related

Microsoft Project VBA to update Custom field on task change

I have been wracking my brain trying to work out how to write a small piece of code that will activate only when particular fields at a task level have been modified.
I tried to make this code work at the project change level with a for each loop and select cases but that lags the whole program and still doesn't give me the result I need. I also tried to make it work when run manually with a for each loop and select cases or a bunch of If statements, but again, it can't tell me which field changed, but it can highlight a discrepancy between two fields.
The goal is to have a change log field (Text10) that auto updates based on the field that is modified and the date of the change. I only care about 4 fields changing (Date1, Date2, Date3, Date4).
e.g. If [Date1] is modified, Text10 = "Date1 modified 10/11/21"
Note: If 2 fields are modified, I would be happy enough with just listing the last one.
I was hoping there was some sort of "On Change, If Target = xxx" but I have not been able to find anything like that.
I also tried implementing the code as defined here >> Microsoft Documents: Project.Change Event but I am unclear what this is supposed to do and couldn't actually see it doing anything / I never got the message box I believe was supposed to appear.
I am using Microsoft Project Standard 2019.
After much research and trial and error, I ended up solving this.
To get it working, I added a Class Module and ran a piece of code on open to initialize it. This essentially tells Project to start watching for events. I then use the "Field" variant to fill the field name amongst the text string and "NewVal" variant to fill the result. This was an easy solution in the end. The code I found that worked is below:
In Class Module "cm_Events"
Public WithEvents MyMSPApp As MSProject.Application
Private Sub Class_Initialize()
Set MyMSPApp = Application
End Sub
Private Sub MyMSPApp_ProjectBeforeTaskChange(ByVal tsk As Task, ByVal Field As PjField, ByVal NewVal As Variant, Cancel As Boolean)
'What you want the code to do
End Sub
In Module "m_Events"
Public oMSPEvents As New cm_Events
Sub StartEvents()
Set oMSPEvents.MyMSPApp = MSProject.Application
End Sub
In ThisProject code
Private Sub Project_Open(ByVal pj As Project)
Call m_Events.StartEvents
End Sub

Needing Assistance with vb.NET Application

I don't normally post on forums because I try to find information for myself, and ask as an absolute last resort. I've tried scouring the net for answers, but I'm only receiving about half of the answer I'm looking for.
I'm currently building an application that deals with state law. There's one combo box and one text box. One for the offense title, and one for the numerical code for that particular code section. So say if I select "Kidnapping", it prepopulates the text box below it with "11-5-77", for example.
The method I've been using for, oh, about the last hour now, is:
If AWOffenseTitle.Text = "Kidnapping" Then
AWCN.Text = "11-5-77"
ElseIf AWOffenseTitle.Text = "False Imprisonment" Then
AWCN.Text = "11-5-78"
With AWOffenseTitle being the combo box name, and AWCN being the text box name. While this has proved to work perfectly well so far, I'm sure you can imagine with hundreds of offense titles, this is going to take a ridiculously long time. Well, I finally found a spreadsheet with offense titles and their respective title codes. What I'm looking to do is create two text files within a folder in the local directory "Offenses". One with a vertical list of offenses, and one with a vertical list of offense code numbers that populate the same lines in each. What I'm looking to do is populate the combo box with the contents of text file one (which I can do already), but then selecting an offense title will read the second text file and display it's proper title code. That's what has me at a loss. I'm relatively well-versed with vb.NET, but I'm not an expert by any means.
I'm hoping someone here will be able to provide a code example and explain it to me line-by-line so I can gain a better understanding. I want to get more proficient with VB although it's not so popular anymore. I've been using VB since 6.0, but not on a regular basis. More on a sporadic project kind of basis.
I really appreciate any assistance anyone might be able to provide, and if you need more information, I'd be glad to answer any questions. I tried to be as thorough as I could.
Thank you in advance!
First, you need to retrieve your data. I demonstrated using an Sql Server database containing a table named Offenses with columns named OffenseTitle and OffenseCode. You will have to change this code to match your situation.
Private Function GetOffenseData() As DataTable
Dim dt As New DataTable
Using cn As New SqlConnection("Your connection string"),
cmd As New SqlCommand("Select OffenseTitle, OffenseCode From Offenses;")
cn.Open()
dt.Load(cmd.ExecuteReader)
End Using
Return dt
End Function
As the Form loads, set the properties of the ComboBox. DisplayMember matches the name of the title column and ValueMember is the name of the code column.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim dt = GetOffenseData()
ComboBox1.DisplayMember = "OffenseTitle"
ComboBox1.ValueMember = "OffenseCode"
ComboBox1.DataSource = dt
End Sub
Then when the selected item in the combo changes, just set the .Text property of TextBox to the SelectedValue in the combo and your code appears.
Private Sub ComboBox1_SelectionChangeCommitted(sender As Object, e As EventArgs) Handles ComboBox1.SelectionChangeCommitted
TextBox1.Text = ComboBox1.SelectedValue.ToString
End Sub
There are other ways to do this if your data source is other than a database. Please advise if you need additional help.
In addition to HardCode's comment and Mary's detailed answer, I can only add an answer that's somewhere in between them.
It might be the case, that the information is not taken from a database, but from another source, like a text/data file or a web service. So it might be useful to create an abstraction for the data source you actually use.
First, I create a class or struct that will hold the data for each combo box item.
Class Offense
Public ReadOnly Property Title As String
Public ReadOnly Property Code As String
Public Sub New(title As String, code As String)
Me.Title = title
Me.Code = code
End Sub
End Class
Next, you need a method that retrieves a list of offenses that you can bind to your combo box. It's entirely up to you how you fill/fetch the offenses list. I have simply hard coded your two values here.
Private Function GetOffenseData() As List(Of Offense)
Dim offenses As New List(Of Offense)
offenses.Add(New Offense("Kidnapping", "11-5-77"))
offenses.Add(New Offense("False Imprisonment", "11-5-78"))
Return offenses
End Function
At a certain moment (probably in your form's Load event handler), you need to initialize your combo box. Just like Mary did, I use data binding.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AWOffenseTitle.DropDownStyle = ComboBoxStyle.DropDownList
AWCN.ReadOnly = True
AWOffenseTitle.DisplayMember = NameOf(Offense.Title)
AWOffenseTitle.ValueMember = NameOf(Offense.Code)
AWOffenseTitle.DataSource = GetOffenseData()
End Sub
Note that I use the NameOf operator to get the desired property names of the Offense class. If you ever decide to rename the properties of your Offense class, you will be able to easily detect where they are used, since the compiler will complain if your code still uses the wrong property names somewhere.
Finally, the app needs to react to combo box value changes, so that the text box will show the corresponding offense code. Mary used an event handler for the SelectionChangeCommitted event, but I use a handler for the SelectedIndexChanged event instead:
Private Sub AWOffenseTitle_SelectedIndexChanged(sender As Object, e As EventArgs) Handles AWOffenseTitle.SelectedIndexChanged
AWCN.Text = AWOffenseTitle.SelectedValue
End Sub
(Up to now, I was not aware of the SelectionChangeCommitted event of the ComboBox control. I will need to look into this event to see if it is actually a better choice for this scenario, but I found that the SelectedIndexChanged event does the job just fine, so for now I sticked with that event, since I am more familiar with it.)

How to update a group of combo boxes using Loops

I have a form with combo boxes (cmbPort#) to select up to 8 serial ports. I want to first clear the item list for each, populate them with currently available system ports, and then add the option "Off" to each list. Finally, to set each combo box according to defaults saved in string spName(). I created a GroupBox (gBox1) and dragged each cmbPort onto it but I'm not sure how to reference the controls on it. I'm using VB 2015.
Can you help with VB.NET code to use loops ("For Each" or similar) to do this more efficiently?
Private Sub frmProp_Load(sender As Object, e As EventArgs) Handles MyBase.Load
cmbPort1.Items.Clear()
...
cmbPort8.Items.Clear()
For Each sp As String In My.Computer.Ports.SerialPortNames
cmbPort1.Items.Add(sp)
...
cmbPort8.Items.Add(sp)
Next
cmbPort1.Items.Add("Off")
...
cmbPort8.Items.Add("Off")
cmbPort1.Text = spName(1)
...
cmbPort8.Text = spName(8)
End Sub
Loops are an incredibly useful tool to master. I pitched here some code so you can get the idea, but I was working out of IDE so you might have to apply some fixes to this code to make it work as you want it to.
The main idea is that you shouldn't have to write a line more than once. If you multiply the same operation on several lines of code, you create potential problems for the future. Loops and subs are really helpful to prevent this kind of issues.
Private Sub frmProp_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'This is for later
Dim cmbIndex As Integer = 1
'You basically do the same operations for every Combobox in your list, son only one loop needed
For Each cmbPort As ComboBox In {cmbPort1, cmbPort2, cmbPort3 [...] cmbPort8} 'this is a way to declare an array
'Clear
cmbPort.Items.Clear()
'Add SerialPortNames
For Each sp As String In My.Computer.Ports.SerialPortNames
cmbPort.Items.Add(sp)
Next
'Add "Off"
cmbPort.Items.Add("Off")
'This last one is a little bit trickier because you want to match numbers
'This is the place where you get errors when something doesn't go as planned
'If you need to keep it inside the loop here's a way to achieve that, but honestly I would't do that
'Instead I would suggest that you take this part out of the loop and do it manually
If spName(cmbIndex) IsNot Nothing Then cmbPort.Text = spName(cmbIndex)
cmbIndex += 1
Next
End Sub
You shouldn't consider efficiency into this equation, as this operation will not be called all the time, only on load. I mean: you should always do things in the best way you can, but optimization is sometimes the enemy of good, readable code.

How can I cause a button click to change the image in a picture box?

I'm using VS2010 for VisualBasic, and I'm working with several similar forms. What I need to have happen is for the buttonclick on each page to cycle through the My.Resource images in order: adj_01, adj_02, adj_03,... and each form will have a different three-letter prefix.
This is what I have so far:
It might not be clear, but I'm trying to have the images cycle trough one after the other with each button click. Apparently there is an issue with either my referencing, or that the images are .png format. Simultaneously, I'm trying to have 2 separate label update information with each image change. This is what I have so far with that:
EDIT I just noticed an error that might confuse everyone on the photos: The first lines starting the If statements are checking to see if the PictureBox is empty. Needless to say, I don't know how to do that.
Here you go...
Private Sub NextAdjButton_Click(sender As Object, e As EventArgs) Handles NextAdjButton.Click
If AdjectivesPictureBox.Tag Is Nothing Then
AdjectivesPictureBox.Tag = 0
End If
Dim number As Integer = CInt(AdjectivesPictureBox.Tag)
If number < 5 Then
number = number + 1
AdjectivesPictureBox.Image = My.Resources.ResourceManager.GetObject("adj_" & number.ToString("00"))
AdjectivesPictureBox.Tag = number
End If
End Sub

Multithreading in vb.net to simulate task

I have a program that is doing one task.
For Example i have one list box containing some links.
And on the other hand my program is opening them one by one but i want it to be done faster
i have used for-each loop for that purpose.
All what i want to do is i wanna give every 2 or 3 link to a different thread or if there is any other solution to make it Faster Kindly tell me.
This is a small piece of code from my program.
For value As Integer = 1 To TextBox1.Text
If (value = TextBox1.Text) Then
Exit For
End If
Dim page As String = "-p-" & value
Extractor.ScrapLinks(txturl.Text + page, lstbox)
lbllinks.Text = lstbox.Items.Count
Next
I don't know what Extractor.ScrapLinks actually do, but it seems that you need to access UI thread and you cannot create multiple UI threads so eventually you will process them sequentially
What you can do to improve the solution is to read the data you want from the UI controls and then process that data on a separate thread, after completion you can fill the results into the UI by invoking some method on the UI thread as shown below
Delegate Sub PerformOperationDel(value As Integer)
Sub PerformOperation(value As Integer)
Dim page As String = "-p-" & value
Extractor.ScrapLinks(txturl.Text + page, lstbox)
lbllinks.Text = lstbox.Items.Count
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For value As Integer = 1 To CInt(TextBox1.Text) - 1
lstbox.BeginInvoke(New PerformOperationDel(AddressOf PerformOperation))
Next
End Sub
You can use backgroundworkers but notice that you cannot access UI controls in the DoWork but you can access them on work completed (Refer to: Background worker proper way to access UI)
Best of luck