Get the Name of the button created through code on click event - vb.net

I am adding buttons through code. So there is a container control and every time the user clicks "Add button", a button gets added to the container control this way:
Dim btnItem As New Button
btnItem.Text = strName
btnItem.Name = "btn-" & strName
AddHandler btnItem.Click, AddressOf f_ViewNameInfo
ButtonContainer.Controls.Add(btnItem)
Problem is inside f_ViewNameInfo function, how do I know which button send the command. In this function I want to get the strName part of the button's name and then work from that. I tried to give parameters to the function, but then the AddHandler part of the above code threw errors, as I am not supposed to give parameters there.

Take a look at the definition of the Click event:
Public Event Click(ByVal sender As Object, ByVal e As System.EventArgs)
Define your function f_ViewNameInfo with these two parameters, and the button that raises it can be obtained from the sender parameter (you will need to cast it to a button first with DirectCast(sender, Button)):
Public Sub f_ViewNameInfo(ByVal sender As Object, ByVal e As System.EventArgs)
Dim str As String = DirectCast(sender, Button).Name
End Function
Note that you should add more safety etc around this, such as checking that sender really is a button before attempting to cast it.

Related

How to remove the most recently added control?

I Intended to display an PictureBox in my form when the mouse hovered over another control. I then wanted to use a separate event for when the mouse left the control. This event would remove the displayed PictureBox from controls. However, because my events are private subs, I can't directly access the name of the control in the latter event. A solution to this would be a method that removes the most recently added control. If no such method exists, or there is an alternative way of approaching this problem, any help would be appreciated.
I tried simply using Controls.Remove(), but this requires a parameter. The name of the control as a string did not work either, as the parameter must be a control itself.
Private Sub Tile_MouseEnter(Sender As Object, e As EventArgs)
Dim CloseUpPic As New PictureBox With {Properties}
CloseUpPic.Image = Sender.Image
Controls.Add(CloseUpPic)
Refresh()
End Sub
Private Sub Tile_MouseLeave(Sender As Object, e As EventArgs)
Me.Controls.Remove()
End Sub
The program won't compile due to .Remove() needing a parameter
I expected for the Control to be created and displayed when the mouse entered the tile, and to cease to exist when the mouse left the tile.
For future reference, controls have Tag property which allows you to store whatever you like. In this case, you can store a reference to the newly created PictureBox. Furthermore, the "Sender" parameter tells you which control was the source of the event. You can cast sender to a control, then store the reference. Then, in the leave event, you can cast sender to a control, cast the .Tag to a control, and finally remove it:
Private Sub Tile_MouseEnter(Sender As Object, e As EventArgs)
Dim ctl As Control = DirectCast(Sender, Control)
Dim CloseUpPic As New PictureBox With {Properties}
CloseUpPic.Image = Sender.Image
Controls.Add(CloseUpPic)
ctl.Tag = CloseUpPic
Refresh()
End Sub
Private Sub Tile_MouseLeave(Sender As Object, e As EventArgs)
Dim ctl As Control = DirectCast(Sender, Control)
Dim ctlToRemove As Control = DirectCast(ctl.Tag, Control)
Me.Controls.Remove(ctlToRemove)
End Sub
I ended up using the following code to solve my issue:
For Each Closeup In Controls.OfType(Of CloseUp)
Controls.Remove(Closeup)
Next
I created a new class of my own called Closeup, that inherits PictureBox. I then looped through each Closeup in controls (There was only one but this code works for multiple controls), and removed them.

Add logic inside button click inside a custom control

I am making a custom control that looks like this (there is a label on the right of the button):
I want the user to be able to define what the button does in his code, but still execute some code on the click event on top of the user's code.
What I want to execute :
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.Button1.Enabled = False
Label1.ForeColor = Color.Gray
Label1.Text = "In Progress"
End Sub
then after this is executed the user's on click event would trigger.
How can I achieve this?
With "the user" you mean a developer which uses that user control, right? Well, the most common thing is to raise an event which the next developer can use to implement his own logic. This is exactly the same as you do - you use the Click-Event of the button.
So basically, take your code and add the RaiseEvent below:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.Button1.Enabled = False
Label1.ForeColor = Color.Gray
Label1.Text = "In Progress"
' this does not affect your code but provides a "hook" for
' other developers
RaiseEvent OnButtonClick(Button1)
End Sub
Now you need to define the event itself like this ...
Public Event OnButtonClick(ByVal sender As Control)
... btw, you can pass other stuff (or nothing at all) as arguments. Sending the button as sender is just a habit.
A developer using your user control can attach a so called "Handler" to implement code as soon as the button was clicked, for example:
AddHandler UserControl1.OnButtonClick, AddressOf OnUserControlButtonClick
This code line should only be executed once, so typically it is placed in the Form_Load event.
Now, in this case the button click is routed to a method called OnUserControlButtonClick() which meets the signature of the event: that means it has one argument which is the sender.
Private Sub OnUserControlButtonClick(ByVal sender as Control)
' custom logic here ...
End Sub
There are so many examples on the web, you could start here.

e.target in VB.net

When using flash, I was able to get to the focus of an event by accessing the event's "target" attribute.
so if I remember, it was something similar to.
button1.addEventListener(mouse_click, doSomething);
doSomething(e: Event){
e.target.size = 50000;
}
And I'm looking for the equivalent in VB.
If you can give me it's common name across all languages, I'd be doubly grateful. I don't quite know what to search for aside from "event.target VB.net equivalent, and that's not returning anything.
Thanks in advance.
edit: for those new to flash. By focus, I mean the physical object that was clicked on. So the example given would be accessing the clicked button's size.
In VB you can wire up event handlers declaratively using the WithEvents keyword or imperatively using AddHandler.
Private WithEvents myButton
' OR
Public Sub New
Dim newButton = New Button()
AddHandler newButton.Click, AddressOf MyClickHandler
End New
'To consume it you declare a method as follows:
' The Handles clause is used when declaring WithEvents
Private Sub MyClickHandler(sender As Object, e As EventArgs) Handles myButton.Click
' The sender has a handle on the object that raised the event (aka the button)
Dim btn = DirectCast(sender, Button)
btn.Size = New Size(500, 500)
End Sub
Got it!
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.button.onclick.aspx#Y0
Sub GreetingBtn_Click(ByVal sender As Object, ByVal e As EventArgs)
'When the button is clicked,
'change the button text, and disable it.
Dim clickedButton As Button = sender
clickedButton.Text = "...button clicked..."
clickedButton.Enabled = False
End Sub
The first parameter (sender by default) references the focused object. You can access it as you would any other normal variable, but it's information won't appear in the auto complete list unless you set it "As" that specific data type.
So I ended up with this
Private Sub nw_btn_Click(ByVal sender As System.Windows.Forms.Button, ByVal e AsSystem.EventArgs) Handles nw_btn.Click
sender.Hide()
End Sub

Dynamic button click event handler

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.

how do I catch events on runtime objects

I'm creating a form with a few buttons and a combobox at runtime.
dim f as new form
(blah blah)
then the buttons acceptDescription and rejectDescription are set up...
then the combobox descriptionCombo is set up...
then...
AddHandler acceptDescription.Click, AddressOf handleAcceptedDescription
AddHandler rejectDescription.Click, AddressOf handleRejectedDescription
then I have these two methods to catch the click events... but can't figure out how to reference the other runtime generated controls. (combobox if accepted, form if rejected)
Private Sub handleAcceptedDescription(ByVal sender As System.Object, ByVal e As System.EventArgs)
'stub
'will need to reference the chosen combobox value here
dim acceptedDescription as string = descriptionCombo.selectedValue .tostring
End Sub
Private Sub handleRejectedDescription(ByVal sender As System.Object, ByVal e As System.EventArgs)
'I want to close the runtime created form here, but can't reference it
f.close()
'and return user to main form
Me.Focus()
End Sub
If the code for generating the form is in your main form, then declare the Form variable at the class level of the main form class so you can access it from the event handlers. Same goes for your combobox and text field- you need to make sure the variables are declared outside the scope of the handlers so you can reference them within the handlers.
Why can't you reference it? Just save it as a module/form-level variable and you're set.
In order to avoid global definitions, the best answer is
Private Sub handleRejectedDescription(ByVal sender As System.Object, ByVal e As System.EventArgs)
'sender is a button in this case.
'get the button
dim b as new button
b = ctype(sender,button)
'now get the button's parent form
dim f as new form
f = ctype(b.parent, form)
'now close the form
f.close()
End Sub