Dynamic buttons made with an array and called by addhandler

DPCOLE

New member
Joined
Sep 2, 2009
Messages
3
Programming Experience
Beginner
Hello. I am fairly new to VisualBasic .NET (2008). I'm creating an application that, when a number is entered into the textbox, a new form window is created and populated with buttons.

Each button starts the same command, but with a different parameter (the parameter being the pertinent record number found by the search).'

The records are asset tag numbers.

The procedure works fine if there is only one result.

But the search allows for partial numbers and that's where the trouble begins.

If two or more results are found, each button is configured with the last number found. The button being clicked doesn't tally with the proper ID number. (Note: Each button made displays the record number found. )

Here's the code and I'll explain other aspects of it:

VB.NET:
                For Each Line In File.ReadAllLines(fileSpecX)
                    Dim pcArray As String() = Line.Split(New Char() {","c})  'strips ALL after the first value's comma - in this case all domain info after the computer name - one dimensional array
                    j = pcArray(i).Length
                    Dim btn(i) As Button
                    pcArray(i) = pcArray(i).Substring(4, (j - 4)) ' truncates "CN=

                    ' removing textbox and dropdown
                    '                    Form3_PC_buttons.foundPcComboBox.Items.Add(pcArray(i))
                    '                    fullScreen = fullScreen + pcArray(i) + Environment.NewLine ' populates display for textbox

                    ' Form3_PC_buttons.btn(i) = New Button
                    btn(i) = New Button
                    btn(i).Location = New Point(k, l)

                    btn(i).ForeColor = White
                    btn(i).BackgroundImage = My.Resources.blue

                    btn(i).SetBounds(k, l, 80, 20)

                    btn(i).Text = pcArray(i)

                    Form3_PC_buttons.Controls.Add(btn(i))

' fill "dummy" value to be carried over, as delegation currently works only with one variable being crossed over.  
'Two created a mismatch and, so far, has not been able to be fixed.
                    Form3_PC_buttons.placeHolder_Form3.Text = pcArray(i) 

                    AddHandler btn(i).Click, AddressOf DynamicClick

                    i += i
                    ' k += 1
                    l += 25

                    tcount += 1
                    mcount += 1

                    If mcount = 3 Then
                        k += 90
                        l = 10
                        mcount = 0
                    End If

                Next

VB.NET:
    Private Sub DynamicClick(ByVal sender As System.Object, ByVal pcNameInfo As System.Object, ByVal e As System.EventArgs)

        sender = Form3_PC_buttons.placeHolder_Form3.Text  ' replace piped data with the name of the PC, placed in the hidden field, we want to remote in to.

        RemoteIn(pcNameInfo)
    End Sub

In the DynamicClick sub, the "sender" variable is a button type and cannot be converted to string. Hence this value being altered to read the value in Form3_text.

What I didn't count on was that the event is only called when a button is clicked. When buttons are made, they are not assigned at that time.

I've had problems trying to carry over the (current value) for pcArray(i), hence having it populate that form3_text field. When trying to add in a second object to be passed, I get the following error:

"Method prtivate sub DynamicClick(sender as object, pcNameInfo as object, e as system.eventargs) does not have a signature compatible with delegate sub event handler with delegate 'delegate sub eventhandler(sender as object e as system.eventargs)."

I tried manually entering a "Delegate sub eventhander" with the pcNameInfo object and VB 2008 ignores it.

What can I do to get each newly made button to be told to run the RemoteIn(pcArray(i)) process properly?

Thank you much!!
 
Firstly, your Button.Click handler. It must follow this pattern
VB.NET:
Private Sub anyNameYouCareToGiveIt(sender As Object, e As EventArgs) Handles yourButton.Click

Given the above, the line in your code would become
VB.NET:
    AddHandler btn(i).Click, AddressOf anyNameYouCareToGiveIt

Secondly, passing the text value across.
Every Control in .NET has a Tag property, this is of type Object and can therefore hold almost anything. It is very useful in situations like yours.

So in your code, where you create each button, simply put the text you want carried over into the Tag property of the button. Something like this:
VB.NET:
    btn(i) = New Button
    btn(i).Location = New Point(k, l)

    btn(i).ForeColor = White
    btn(i).BackgroundImage = My.Resources.blue

    btn(i).SetBounds(k, l, 80, 20)

    btn(i).Text = pcArray(i)

    btn(i).Tag = pcArray(i)    '<================= HERE

    Form3_PC_buttons.Controls.Add(btn(i))

Then all you have to do in the Click event handler is to retrieve the value of the Tag and cast it to String. Something like:
VB.NET:
    Private Sub anyNameYouCareToGiveIt(sender As Object, e As EventArgs) Handles yourButton.Click
        ' 1) get sender and cast it to Button
        Dim btn As Button = CType(sender, Button)
        ' 2) get the Tag property for the button and  cast it to String
        Dim passedString As String = CType(btn.Tag, String)
    End Sub

I hope this helps you to resolve at least some of your problems. :)
 
:):D:)

Thank you so much!!! I was utterly clueless about the .Tag property, and it's working beautifully!

I do have one remaining question:

VB.NET:
Private Sub anyNameYouCareToGiveIt(sender As Object, e As EventArgs) Handles yourButton.Click

Adding in the "Handles btn.click" results in an error: "Handles clause requires a WithEvents variable defined in the containing type or one of its base types."

Is there a generic button.click entry I could use for the Handles clause? Using IntelliSense as a guide, nothing became apparent... :(

Thanks again!

Dave
 
Sorry, my fault, not thinking clearly.

Here is a bit of code, that might help:
VB.NET:
	Private Sub btnCreateButtons_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCreateButtons.Click
		Dim newButton As Button = Nothing
		Dim yPos As Int32 = 10

		For index As Int32 = 0 To 4
			newButton = New Button()
			newButton.Location = New Point(10, yPos)
			newButton.Text = "btn" & index.ToString()
			newButton.Name = "btn" & index.ToString()
			Me.Controls.Add(newButton)
			AddHandler newButton.Click, AddressOf DynamicClick

			yPos = yPos + 28
		Next
	End Sub

	Private Sub DynamicClick(ByVal sender As System.Object, ByVal e As System.EventArgs)
		Dim btn As Button = CType(sender, Button)
		MessageBox.Show(btn.Name & " clicked")
	End Sub

This is just a new Windows Forms solution with a Button (I have named it 'btnCreateButtons'). Its click event is hooked up to the btnCreateButtons_Click handler.

I typed in the DynamicClick handler, NOTE that it has no 'Handles' clause.

I don't know if this is an 'approved' method, but it seems to work. :D
 
You basically have 2 options when creating dynamic controls:
1) use Private WithEvents ... and use the handles clause, or
2) use addhandler statement and no handles clause.

When multiple controls use the same event, the sender object is the current object being used -

VB.NET:
Private Sub MyClick(ByVal sender As Object, ByVal e As EventArgs)
   If sender.Text = "blah" Then
     'do something
   End If
End Sub
 
Thanks for that. :)

Good to know these things.
 
Back
Top