pass variable into dynamically created button click event handler - vb.net

I am creating a textbox and button dynamically like this inside a FlowLayoutPanel:
Dim txtRating As New TextBox
txtRating.Name = "buildingRating_" + intCount.ToString
Dim btnAddRating As New Button
btnAddRating.Name = "addRating_" + intCount.ToString
And then I create an event handler for the button:
AddHandler btnAddRating.Click, AddressOf HandleAddRatingButtonClick
Each textbox and button will be associated with each other with the intCount value, so it would look like this:
buildingRating_1 addRating_1
buildingRating_2 addRating_2
buildingRating_3 addRating_3
etc....
I need to get the value of the textbox that is in associated with the button.
For example, if the user clicks the button named addRating_1, the text value of buildingRating_1 will be saved a database...
Is there a way to get that association or pass intCount into the btnAddRating.Click event that I am creating?
Thanks!

Extract the index from the name of the button, and use it to recreate the name of the textbox. Then find the textbox on the form.
Private Sub HandleAddRatingButtonClick(sender As Object, e As EventArgs)
Dim button = DirectCast(sender, Button)
Dim index = button.Name.Split("_"c).Last()
Dim textboxname = "buildingRating_" & index
Dim textbox = Me.Controls.OfType(Of TextBox).Single(Function(tb) tb.Name = textboxname)
Dim text = textbox.Text ' this is the text
End Sub
If the textbox is in a container (panel, groupbox, etc.) then instead of Me.Controls... do Container.Controls...

Related

How to reference a variable control on a variable form from another form? Need to get the button.Tag renamed in running program

Here's my problem:
I have a form with a treeview.
That treeview shows all:
other forms in my project as parents
all buttonnames as childs
all buttontags as childs of the buttonnames.
When i select a buttonname in the treeview i have the selection presented as
(textbox1 with the buttonname)
(textbox2 with the buttontag)
(textbox3 with the formname)
I have 1 empty textbox which i want to fill manually, to update the buttontag from the button selected in the treeview.
Either way, all code I have tried ain't updating anything.
This is the code so far, but doesn't seem to work...
My Code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim asm = System.Reflection.Assembly.GetExecutingAssembly
Dim myTypes As Type() = asm.GetTypes()
Dim frm As Form
For Each t As Type In myTypes
If t.IsSubclassOf(GetType(System.Windows.Forms.Form)) AndAlso TextBox1.Text = t.Name Then
frm = CType(Activator.CreateInstance(t), Form)
frm.Hide()
Dim thisButtonName As String = TextBox3.Text ' This is the name of the button I'm looking for
Dim thisButtonName2 As String = TextBox2.Text ' this is the new tag name for that button
' Loop all controls in this form
For Each ctrl As Control In Controls
' Is this control a button
If TypeOf (ctrl) Is Button Then
' Is this the correct button
If CType(ctrl, Button).Name = thisButtonName Then
CType(ctrl, Button).Tag = thisButtonName2
End If
End If
Next
End If
Next
TreeView1.Nodes.Clear()
For Each formprop In My.Forms.GetType.GetProperties
Dim node = Me.TreeView1.Nodes.Add(formprop.Name)
Dim form As Form = CType(formprop.GetValue(My.Forms, Nothing), Form)
ControlsTree(node, form.Controls)
Next
End Sub
I think there are two basic problems here:
Your loop For Each ctrl As Control In Controls is not iterating over the controls in the other form object referenced by the frm variable. The Controls property is going to default to this form's set of Controls, not frm.Controls.
It seems like you are trying to change the Tag in the definition of that class at run-time. That is not possible, AFAIK, especially in what you're trying here. Each time you create a new instance of that form object, you are going to get that object initialized as how it was compiled. You can change the Tag values of a running instance of the object, but you can't change the default values of the class without using a technique like dependency injection.

Creating multiple click events for dynamic buttons in vb.net

When creating a button I want to create a click event for each button. How do I create a click event for each button created dynamically? Here is my code. It works to create a single event based on the first button created.
Sub CreateDynamicButton()
Dim ButtonNumber As Integer = 1
Dim axisX As Integer = 53
Dim axisY As Integer = 13
' Create a Button object
Do Until ButtonNumber = 11
Dim dynamicButton As New Button
' Set Button properties
dynamicButton.Location = New Point(axisX, axisY)
dynamicButton.Height = 30
dynamicButton.Width = 200
' Set background and foreground
dynamicButton.BackColor = Color.Beige
dynamicButton.ForeColor = Color.Black
dynamicButton.Text = "I am Dynamic Button" & ButtonNumber
dynamicButton.Name = "DynamicButton" & ButtonNumber
dynamicButton.Font = New Font("Georgia", 10)
AddHandler dynamicButton.Click, AddressOf dynamicButton_Click
' Add Button to the Form. Placement of the Button
' will be based on the Location and Size of button
Controls.Add(dynamicButton)
axisY = axisY + 35
ButtonNumber = ButtonNumber + 1
Loop
'Add Exit Button
Dim dynamicButtonExit As New Button
' Set Button properties
dynamicButtonExit.Location = New Point(axisX, axisY)
dynamicButtonExit.Height = 30
dynamicButtonExit.Width = 200
' Set background and foreground
dynamicButtonExit.BackColor = Color.Beige
dynamicButtonExit.ForeColor = Color.Black
dynamicButtonExit.Text = "Exit"
dynamicButtonExit.Name = "Exit"
dynamicButtonExit.Font = New Font("Georgia", 10)
AddHandler dynamicButtonExit.Click, AddressOf dynamicButtonExit_Click
' Add Button to the Form. Placement of the Button
' will be based on the Location and Size of button
Controls.Add(dynamicButtonExit)
End Sub
You don't need to create multiple event to handle your dynamic buttons, dynamicButton_Click is enough to handle all click. Better give ID for each button and you only need to do is in this event, do code as below:
Dim btn As Button = DirectCast(sender, Button)
If btn.ID = "DynamicButton1" then
'Do logic here for button 1
End If
You just need to add a little logic to handle each button click in the one event handler. If you use as 'Select Case' Statement it keeps things tidy as well.
If you have a lot of code for each button's logic, it may be better to write separate subs for each button and call the appropriate sub using each 'Case' block like in the second case block
Private Sub DynamicButton_click(sender As Object, e As EventArgs)
Dim btn As Button = DirectCast(sender, Button)
Select Case btn.Name
Case "DynamicButton1"
MessageBox.Show("button1")
Case "DynamicButton2"
dynamicbutton2_Click(sender, e)
End Select
End Sub
Private Sub dynamicbutton2_Click(sender As Button, e As EventArgs)
MessageBox.Show("Button2")
'and lots of other code
End Sub

Update text in dynamically created label

I'm working on a proof of concept type situation that will eventually be tied to a scheduling database. As a Test I created this:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'AddButton("test")
addLots()
End Sub
Private Sub AddLots()
Dim x As Integer
For x = 0 To 10
Dim b As New Button
Dim newLabel As New Label
newLabel.Location = New Point(100, x * 20)
newLabel.Name = x
newLabel.BorderStyle = BorderStyle.Fixed3D
newLabel.Text = newLabel.Name
Me.Controls.Add(newLabel)
Me.Controls.Add(b)
b.Location = New Point(20, x * 20)
b.Text = x
b.Tag = x
b.Name = x
AddHandler b.Click, AddressOf Button_Click
Next
End Sub
Private Sub Button_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim B As Button = sender
MsgBox(B.Name)
End Sub
For this proof of concept, I simply want label 1 text to be updated when I press button 1 seems like a simple process but it's kicking my butt.
As for any object, to affect a Label you will need a reference to it. As it stands, the only reference you have is via the Controls collection of the parent control you added the Label to, i.e. the form itself. You could loop through the Controls of the form and as soon as you find a Label then you know you have the first one, or you could call OfType and First or FirstOrDefault. That assumes that there are no other Label controls on the form.
You might also consider using a dedicated parent control so that you know it will only contain the Label controls you created at run time. The obvious choice would be a TableLayoutPanel because it will handle the layout for you too.
If accessing the dynamic controls via a Controls collection is an issue then keep your own collection. Declare a member variable of type List(Of Label) and add each Label you create to it. You can then access your control from that collection and know that there are no other controls in there to get mixed up with.
By the way, if you're creating those controls at run time then they won't be automatically disposed when the form is. Make sure that you dispose them yourself and also use RemoveHandler for each AddHandler you used.
Actually, looking closer at your code, I just realised that there's a 1:1 correspondence between the Button and Label controls. It would make sense to use that. Two options are to assign the corresponding Label to the Tag of each Button or else use a Dictionary(Of Button, Label) assigned to a member variable to store the relationships. That way, you can then use the sender in the event handler, which will be the Button that was clicked, to get the corresponding Label.
Option 1.
Creating the Label:
Dim btn As New Button
Dim lbl As New Label
btn.Tag = lbl
In the event handler:
Dim btn = DirectCast(sender, Button)
Dim lbl = DirectCast(btn.Tag, Label)
Option 2.
At class level:
Private labelsByButton As New Dictionary(Of Button, Label)
Creating the Label:
Dim btn As New Button
Dim lbl As New Label
Me.labelsByButton.Add(btn, lbl)
In the event handler:
Dim btn = DirectCast(sender, Button)
Dim lbl = Me.labelsByButton(btn)
I added this to the button click event. Doesn't seem very efficient as I will eventually have 30-40 buttons and controls on the form but it works.
Private Sub Button_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim B As Button = sender
Dim lblToChange As Integer = B.Name
For Each objCtrl As Control In Me.Controls
If TypeOf objCtrl Is Label Then
Dim Lbl As Label = DirectCast(objCtrl, Label)
If Lbl.Name = lblToChange Then
Lbl.Text = "This ONe"
End If
End If
Next
End Sub

How to manage dynamically created controls in VB.NET?

I just understand how to make controls dynamically in VB.NET (I mean, only part of adding a new one)
But, unlike VB6, it seems hard to handle those dynamic things.
When I click the DONE button, I want to make an array filled with the text of textboxes.
At the same time, I want to make a Delete button that removes the button itself and the textbox in the same line.
Is there any simple method or an sample code for this?
Thank you!
Drop a TableLayoutPanel on your form, called pnlLayout, and also the Add button called btnAdd. Configure TableLayoutPanel to have two columns, adjust column width as needed.
Paste below code into your form:
Public Class Form1
Dim deleteButtons As List(Of Button)
Dim textBoxes As List(Of TextBox)
Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
deleteButtons = New List(Of Button)
textBoxes = New List(Of TextBox)
End Sub
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
Dim elementCount As Integer = deleteButtons.Count
Dim txt As New TextBox
txt.Width = 100
txt.Height = 20
textBoxes.Add(txt)
Dim btn As New Button
btn.Width = 100
btn.Height = 20
btn.Text = "Delete " & elementCount.ToString
AddHandler btn.Click, AddressOf btnDelete
deleteButtons.Add(btn)
pnlLayout.SetCellPosition(txt, New TableLayoutPanelCellPosition(0, elementCount))
pnlLayout.SetCellPosition(btn, New TableLayoutPanelCellPosition(1, elementCount))
pnlLayout.Controls.Add(btn)
pnlLayout.Controls.Add(txt)
End Sub
Private Sub btnDelete(sender As Object, e As EventArgs)
Dim senderButton As Button = DirectCast(sender, Button)
Dim txt As TextBox = textBoxes(deleteButtons.IndexOf(senderButton))
pnlLayout.Controls.Remove(senderButton)
pnlLayout.Controls.Remove(txt)
End Sub
End Class
By default, it will have no textboxes and no Delete buttons, you can add as many rows of "Textbox + Delete button" as you want. When you press Delete, the row will be removed (and everything shifted to accommodate the empty space).
For the textbox'ex part:
Dim strcol() As String = {TextBox2.Text, TextBox3.Text}
For Each strtxt In strcol
MessageBox.Show(strtxt)
Next
It really depends on your code, but, if you have their name use this to delete the buttons &/ textbox'es:
For i As Integer = Me.Controls.Count - 1 To 0 Step -1
If TypeOf Me.Controls(i) Is TextBox Then
If Me.Controls(i).Name = "TextBox2" Then
Me.Controls.RemoveAt(i)
End If
End If
If TypeOf Me.Controls(i) Is Button Then
If Me.Controls(i).Name = "Button3" Then
Me.Controls.RemoveAt(i)
End If
End If
Next
But it depends on your code...

How to access a label in datalist when a button is clicked in the same row

I have a DataList, and each data list has a label and button, I want to get the text of the label when the button is clicked for each data list row ?
I am using vb.net.
I assume that you're handling the DataList's ItemCommand event by setting the Button's CommandName property.
Sub Item_Command(sender As Object, e As DataListCommandEventArgs)Handles DataList1.ItemCommand
' What command was triggered?
If e.CommandName = "YourCommandName" Then
' Get the Label in the DataListItem of the clicked button
Dim lbl = DirectCast(e.Item.FindControl("Label1"), Label)
Dim labelText = lbl.Text
End If
End Sub