Dynamic button click event handler - vb.net

I've 100 buttons created dynamically in a form. How can I an add event handler to them?

You can use AddHandler to add a handler for any event.
For example, this might be:
AddHandler theButton.Click, AddressOf Me.theButton_Click

Just to round out Reed's answer, you can either get the Button objects from the Form or other container and add the handler, or you could create the Button objects programmatically.
If you get the Button objects from the Form or other container, then you can iterate over the Controls collection of the Form or other container control, such as Panel or FlowLayoutPanel and so on. You can then just add the click handler with
AddHandler ctrl.Click, AddressOf Me.Button_Click (variables as in the code below),
but I prefer to check the type of the Control and cast to a Button so as I'm not adding click handlers for any other controls in the container (such as Labels). Remember that you can add handlers for any event of the Button at this point using AddHandler.
Alternatively, you can create the Button objects programmatically, as in the second block of code below.
Then, of course, you have to write the handler method, as in the third code block below.
Here is an example using Form as the container, but you're probably better off using a Panel or some other container control.
Dim btn as Button = Nothing
For Each ctrl As Control in myForm.Controls
If TypeOf ctrl Is Button Then
btn = DirectCast(ctrl, Button)
AddHandler btn.Click, AddressOf Me.Button_Click ' From answer by Reed.
End If
Next
Alternatively creating the Buttons programmatically, this time adding to a Panel container.
Dim Panel1 As new Panel()
For i As Integer = 1 to 100
btn = New Button()
' Set Button properties or call a method to do so.
Panel1.Controls.Add(btn) ' Add Button to the container.
AddHandler btn.Click, AddressOf Me.Button_Click ' Again from the answer by Reed.
Next
Then your handler will look something like this
Private Sub Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
' Handle your Button clicks here
End Sub

#Debasish Sahu, your answer is an answer to another question, namely: how to know which button (or any other control) was clicked when there is a common handler for a couple of controls? So I'm giving an answer to this question how I usually do it, almost the same as yours, but note that also works without type conversion when it handles the same type of Controls:
Private Sub btn_done_clicked(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim selectedBtn As Button = sender
MsgBox("you have clicked button " & selectedBtn.Name)
End Sub

I needed a common event handler in which I can show from which button it is called without using switch case... and done like this..
Private Sub btn_done_clicked(ByVal sender As System.Object, ByVal e As System.EventArgs)
MsgBox.Show("you have clicked button " & CType(CType(sender, _
System.Windows.Forms.Button).Tag, String))
End Sub

Some code for a variation on this problem. Using the above code got me my click events as needed, but I was then stuck trying to work out which button had been clicked.
My scenario is I have a dynamic amount of tab pages. On each tab page are (all dynamically created) 2 charts, 2 DGVs and a pair of radio buttons. Each control has a unique name relative to the tab, but there could be 20 radio buttons with the same name if I had 20 tab pages. The radio buttons switch between which of the 2 graphs and DGVs you get to see. Here is the code for when one of the radio buttons gets checked (There's a nearly identical block that swaps the charts and DGVs back):
Private Sub radioFit_Components_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
If sender.name = "radioFit_Components" And sender.visible Then
If sender.checked Then
For Each ctrl As Control In TabControl1.SelectedTab.Controls
Select Case ctrl.Name
Case "embChartSSE_Components"
ctrl.BringToFront()
Case "embChartSSE_Fit_Curve"
ctrl.SendToBack()
Case "dgvFit_Components"
ctrl.BringToFront()
End Select
Next
End If
End If
End Sub
This code will fire for any of the tab pages and swap the charts and DGVs over on any of the tab pages. The sender.visible check is to stop the code firing when the form is being created.

Related

loop button to check which was clicked

In VB.net form, I have 20 buttons. They are named from btnLoc1 ~ btnLoc20. I do not want to code each button click event.
How to loop through each button to check which was clicked?
Do I need to implement timer tick to listen for button click event?
You can create a single event handler for all the Buttons. Select all the buttons in the designer, open the Properties window, click the Events button and then double-click the Click event. That will generate a Click event handler, just like when you double-click a Button in the designer, except this one will have multiple items in the Handles clause. You can then use the sender parameter to acces the Button that was clicked, e.g.
Private Sub Buttons_Click(sender As Object, e As EventArgs) Handles Button1.Click,
Button2.Click,
Button3.Click
Dim btn = DirectCast(sender, Button)
'Use btn here.
End Sub
The question then is, what do you want to do with that Button? If you want to do something different for each Button then you really should be creating separate event handlers. Alternatively, you might have a list of data and you want to use the item in that list that corresponds to the Button that was clicked. There are numerous ways to do that. One is to put the data in the Tag property of the Button itself and retrieve it from there. Another is to use concurrent indexes, e.g.
Dim buttons = Controls.OfType(Of Button)().ToArray()
Dim data = {"First", "Second", "Third"}
MessageBox.Show(data(buttons.IndexOf(btn)))
Obviously you need to ensure that the Button array and the data array do line up.
For being noticed if button was clicked - eventhandler is best choice.
But you can create only one eventhandler for all buttons
Private Sub Button_Click(sender As Object, e As EventArgs)
Dim button As Button = DirectCast(sender, Button)
MessageBox($"Button '{button.Name}' was clicked")
End Sub
Then in constructor
Public Sub New()
InitializeComponennts()
AddHandler Button1.Click, AddressOf Me.Button_Click
AddHandler Button2.Click, AddressOf Me.Button_Click
AddHandler Button3.Click, AddressOf Me.Button_Click
' and so on
End Sub
If you want to get information about how much each button was clicked, simply create dictionary and add click amount in one eventhandler
Private ButtonsClickAmount As New Dictionary(Of String, Integer)()
Private Sub Button_Click(sender As Object, e As EventArgs)
Dim button As Button = DirectCast(sender, Button)
If ButtonsClickAmount.ContainKey(button.Name) = True Then
ButtonsClickAmount(button.Name) += 1
Else
ButtonsClickAmount.Add(button.Name, 1)
End If
End Sub

How to use dynamically added toolstripmenuitem

I'm trying to make a tool strip item that contains bookmarks and each bookmark should go to the page. How do make each button work?.
For Each b In New System.IO.DirectoryInfo("Bookmarks").GetFiles
BookmarksToolStripMenuItem.DropDownItems.Add(b.Name)
Next
You should first create a too ToolStripMenuItem, then add handlers and put it to your toolstripmenu object instead of adding to toolstripmenu a string object.
For Each b In New System.IO.DirectoryInfo("Bookmarks").GetFiles
Dim menuItem As New ToolStripMenuItem(b.Name)
'Add any handlers here
'Click handler to your menuItem.
AddHandler menuItem.Click, AddressOf menuItem_Click 'CLICK EVENT HANDLER ALSO UNIQUE
'Add menuItem to ToolStripMenu
BookmarksToolStripMenuItem.DropDownItems.Add(menuItem)
Next
Private Sub menuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
'CODE TO HANDLE CLICK EVENT
End Sub
If you don't know how to dynamicaly add handlers then take a look at examples.

Open Tabs Control

I'm using MDI container to run my bussiness application I created for my client.
Since using MDI means that when I open several forms they will still run in background all the time untill I close them manualy.
What I need is to make User Control or anything else that could preview all opened forms in Tab Form so my client can easily close all or some of opened forms without closing a form he is curently viewing.
For now I have used this code, so for now only first clicked item from menu appears as button, but not others clicked menu items.
Private Sub MenuStrip1_ItemClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles MenuStrip1.ItemClicked
Dim Button As New Button
Me.Panel5.Controls.Add(Button)
Button.Text = e.ClickedItem.Name
Button.Width = 50
Button.Height = 25
End Sub
Now I need to write a code to add more buttons bellow, also should add a code for adding buttons only when I click on SubMenu item (The one when is clicked new Form appear).
And also, I should now add a little Close button into previewed User-Button-Control.
From your comments, I understand that your ideas regarding adding buttons at runtime are not too clear and thus I am including a small code which hopefully will help you on this front. Start a new project and put a Panel (Panel5) and a Button (AddButtons) on it, and write this code:
Dim lastButtonIndex, lastLeft, lastTop As Integer
Private Sub Button_Click(sender As System.Object, e As System.EventArgs)
Dim curButton As Button = DirectCast(sender, Button)
If (curButton.Name = "Button1") Then
'do Button1 stuff
End If
'etc.
End Sub
Private Sub addNewButton()
lastButtonIndex = lastButtonIndex + 1
lastLeft = lastLeft + 5
lastTop = lastTop + 5
Dim Button As New Button
With Button
.Name = "Button" + lastButtonIndex.ToString()
.Text = "Button" + lastButtonIndex.ToString()
.Width = 50
.Height = 25
.Left = lastLeft
.Top = lastTop
AddHandler .Click, AddressOf Button_Click
End With
Me.Panel5.Controls.Add(Button)
End Sub
Private Sub ButtonAddButtons_Click(sender As System.Object, e As System.EventArgs) Handles AddButtons.Click
addNewButton()
End Sub
This code will add a new button to the panel every time you click on AddButtons. All the buttons will have an associated Click Event (the same one for all of them): Button_Click. The way to know which button is the current one inside this method is via sender, as shown in the code (you can put as many conditions as buttons. The names are given sequentially starting from 1; but you can take any other property as reference, curButton is the given Button Control).
Bear in mind that one of the problems you have to take care of is the location of the buttons. The code above has a very simplistic X/Y values (Left/Top properties) auto-increase which, logically, will not deliver what you want.

Detecting a radiobutton change

I have about 50 radiobuttons on one form and I don't want to create an if statement for each one to detect when one changes, they are not part of a group box. How would I detect if any radiobutton changed and then write the name to another variable?
Put all the radio buttons on a panel and loop through the panels radio button controls, programmatically adding the same event handler for each as described by #Steve. One way I like to handle the event is to assign each radio button an index into its tag property. Then just store any relevant data in a list of objects and access the data for that radio button by pulling out it's corresponding object from the list using its tag. Much easier than doing it by hand.
Edit: Good catch #Neolisk. Updated answer.
You could Always set the CheckedChanged event for all 50 radiobuttons to the same event handler.
This is an example done via code:
Private Sub OnChange(sender As System.Object, e As System.EventArgs)
Dim rb = CType(sender, RadioButton)
Console.WriteLine(rb.Name + " " + rb.Checked.ToString)
End Sub
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
AddHandler Me.RadioButton1.CheckedChanged, AddressOf OnChange
AddHandler Me.RadioButton2.CheckedChanged, AddressOf OnChange
' and so on .....'
End Sub
I have done this via code and not using the designer to avoid the long add of Handles RadioButton1.CheckedChanged, RadioButton2.CheckedChanged .......

Right click: menu options

there is a feature I'd like to implement in my application:
The user right clicks on my picturebox object. Good.
When that happens, some code of mine executes and will generate a list of options.
Then a menu appears where the mouse right-clicked, made up of these options.
When the user clicks on one of these options, the menu is deleted and some code is run given the option index as parameter.
My two problems:
How can I tell when the user right clicks? I can see an event handler for "click", but that includes left clicks....
How do I create one of these menus? I mean, go ahead and right click something. That's the kind of menu I'm looking for.
You need to implement the picturebox' MouseUp event. Check if the right button was clicked, then create a ContextMenuStrip with the menu items you want. You can use, say, the Tag property of the items you add to help identify them so you can give them a common Click event handler. Like this:
Private Sub PictureBox1_MouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseUp
If e.Button <> Windows.Forms.MouseButtons.Right Then Return
Dim cms = New ContextMenuStrip
Dim item1 = cms.Items.Add("foo")
item1.Tag = 1
AddHandler item1.Click, AddressOf menuChoice
Dim item2 = cms.Items.Add("bar")
item2.Tag = 2
AddHandler item2.Click, AddressOf menuChoice
'-- etc
'..
cms.Show(PictureBox1, e.Location)
End Sub
Private Sub menuChoice(ByVal sender As Object, ByVal e As EventArgs)
Dim item = CType(sender, ToolStripMenuItem)
Dim selection = CInt(item.Tag)
'-- etc
End Sub
To your first question: you actually handle just the "click" event, there is no separate event for right-click. But look at the EventArgs object you get passed for the event: it includes information of which button was pressed (and would give you more info if a mouse click had anything beyond that). So you check the button within an if block, and you're good to go.
To your second question: http://msdn.microsoft.com/en-us/library/system.windows.forms.contextmenustrip.aspx. If your menu is pre-defined, just look for that component on the Designer and prepare the menu from there and call its Show() method from the click handler. If you need to decide the menu entries on the fly, the linked documentation page actually includes an example on that ;)
PS: oops, I just noticed Jon's comment on the question. The answer I gave you is for Windows Forms. If you are on WPF let us know and I'll update with the details (although the concepts ain't too different).
There is actually an easier way to do this. Double-click on the control you wish to be able to right click. Now go to the top of the page and it should say in comboboxes; 'Control' and 'Click' Click on the 'click' combobox and look for: Right-Click. Use a ContextMenuStrip for your right click menu.
Now you can choose which function you want.
Private Sub PictureBox1_RightClick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.RightClick
ContextMenuStrip1.Show()
MsgBox("Content Activated.", MsgBoxStyle.Information, "Success!")
End Sub
Hope I could help. :)
Coridex73