Labels' Click events - vb.net

I have an application where I have around 50 labels. In those labels a number is visible.
When the user clicks on the label the number needs to be written to an edit box.
This works fine, the only problem is that I have added 50 functions like below, and every time it’s the same. I was wondering if there is a common function for this
Remark: The labels have different names. So if its possible that this will work for all the labels on the form.
Private Sub LI_L_Click(sender As Object, e As EventArgs) Handles LI_L.Click
cmbOBJID.Text = LI_L.Text
End Sub

In the form designer, you should be able to set the handler for every label to the same function. Then you can use the "sender" parameter to determine which label is raising the event.
Notice also how all the controls that the function is linked to are listed after the "Handles" keyword. This is another way you could connect the code to all the labels if you prefer this over using the Visual Studio UI properties grid.
Private Sub LI_Click(sender As Object, e As EventArgs) Handles Label1.Click, Label2.Click, Label3.Click
cmdOBJID.Text = DirectCast(sender, Label).Text
End Sub

While it is easy to add several events to one handler in the style of
Private Sub LI_Click(sender As Object, e As EventArgs) Handles Label1.Click, Label2.Click, Label3.Click
It will be tedious for more than just a few labels.
You can add handlers programatically if you can find a way to refer to the labels you need to add handlers to. In this example, I put all the labels in a groupbox named "GroupBoxOptions":
Option Infer On
Option Strict On
Public Class Form1
Sub TransferDataToEditBox(sender As Object, e As EventArgs)
Dim lbl = DirectCast(sender, Label)
tbEditThis.Text = lbl.Text
End Sub
Sub InitLabelHandlers()
For Each lbl In GroupBoxOptions.Controls.OfType(Of Label)
AddHandler lbl.Click, AddressOf TransferDataToEditBox
Next
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
InitLabelHandlers()
End Sub
End Class
You may have some other way of selecting the labels which use the handler.

A pretty nice and quick solution is to traverse all the label controls on a form, assigning through the AddHandler function the event to run when a user clicks a label.
In code:
For Each c As Control In Me.Controls.OfType(Of Label)
AddHandler c.Click, AddressOf myLabelClick
Next
With the prevous snippet, we loop onto all the winform controls of type Label. A loop like that is useful when we have a lot of labels for which an event must be assigned. For each of them, we associate the event Click of the control with a customized Sub named myLabelClick. That subroutine will look like the following:
Private Sub myLabelClick(sender As Object, e As EventArgs)
cmdObjId.Text = DirectCast(sender, Label).Text
End Sub
Here we use the sender variable (which represents the control for which the click has been done) to access its Text property, and change the cmdObjId.Text accordingly.

Just to complement the solution from BlueMonkMN:
If you are using the DevExpress Tools, you need to import DevExpress.XtraEditors and change Label to LabelControl:
DirectCast(sender, LabelControl).Text
This worked for me.

Related

Triggering an event in VB based on a change in a control in a group box

I have a group box with multiple Checkboxes(food item) and each one has a corresponding NumericUpDown control(quantity). For context, it is for a project based on a restaurant menu. I want to hide a button called btnSave whenever either a checkbox is unchecked or the quantity (NumericUpDown) is changed. I currently have btnSave.Hide under the CheckBox1_CheckedChanged and NumericUpDown1_CheckedChanged SubProcedures but I want to know if there's a way to do this when anything within this group box is changed instead of putting the code under each SubProcedure. Thanks
I think you meant .ValueChanged for the NumericUpDown control. (There is no .CheckedChanged) Although this doesn't matter much in this case, this is a good pattern for future reference. Instead of calling an event call a Sub from your events.
When you have several controls responding to a single Event handler, you can find out which control triggered the event by checking the sender parameter. Since, as you can see, sender is an Object you will have to cast it to the appropriate type to get the properties of a CheckBox.
Private Sub HideSaveButton()
btnSave.Hide
End Sub
Private Sub CheckBoxInGroupBox_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox1.CheckedChanged, CheckBox2.CheckedChanged
HideSaveButton()
Dim WhichCheckBox As CheckBox = DirectCast(sender, CheckBox)
Select Case WhichCheckBox.Name
Case "CheckBox1"
MessageBox.Show("CheckBox1 has changed")
Case "CheckBox2"
MessageBox.Show("CheckBox2 has changed")
End Select
End Sub
Private Sub NumericUpDown1_ValueChanged(sender As Object, e As EventArgs) Handles NumericUpDown1.ValueChanged
HideSaveButton()
End Sub

add event on controls - how can i refer to the control itself

I want to add the same event on my multiple textboxes. Let's say for example I want all my textboxes to trim the text value of itself when it has lost focus
my idea is to loop through all the textboxes and to add an event handler to all of it, but how will I refer to the textbox itself, I think it is the same as using the "this" keyword, but it is not available in vb.net - any other recommendations?
In order to get the element which triggered the event you can use the sender parameter of the event and cast it to the required type. It is not clear from the question which platform you are using, but below is the sample code for Windows Forms:
Private Sub txt1_TextChanged(sender As Object, e As EventArgs) Handles txt1.TextChanged
Dim currentTextbox as TextBox = CType(sender, TextBox)
' Do what you want with the textbox
End Sub
Similar principles should apply to Web forms or WPF as well.
Through all the textboxes Use handles for all textboxes
Private Sub TextBox1_LostFocus(sender As Object, e As EventArgs) _
Handles TextBox1.LostFocus, TextBox2.LostFocus
Dim txtBox As TextBox = sender
txtBox.Text = Strings.Trim(txtBox.Text)
End Sub

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 .......

Handling all textbox event in one Handler

I do know how to handle event of textboxes in my form. But want to make this code shorter because I will 30 textboxes. It's inefficient to use this:
Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged, TextBox2.TextChanged, TextBox3.TextChanged, TextBox4.TextChanged, TextBox5.TextChanged, TextBox6.TextChanged, TextBox7.TextChanged, TextBox8.TextChanged, TextBox9.TextChanged, TextBox10.TextChanged
Dim tb As TextBox = CType(sender, TextBox)
Select Case tb.Name
Case "TextBox1"
MsgBox(tb.Text)
Case "TextBox2"
MsgBox(tb.Text)
End Select
End Sub
Is there a way to shorten the handler?
You can use Controls.OfType + AddHandler programmatically. For example:
Dim textBoxes = Me.Controls.OfType(Of TextBox)()
For Each txt In textBoxes
AddHandler txt.TextChanged, AddressOf txtTextChanged
Next
one handler for all:
Private Sub txtTextChanged(sender As Object, e As EventArgs)
Dim txt = DirectCast(sender, TextBox)
Select Case txt.Name
Case "TextBox1"
MsgBox(txt.Text)
Case "TextBox2"
MsgBox(txt.Text)
End Select
End Sub
If you have created very Textbox with the Designer, I don't think there is a better method.
But, if you have created the Textboxes dynamically, you should AddHandler in this way:
For i = 0 to 30
Dim TB as New Texbox
AddHandler TB.TextChanged, TextBox1_TextChanged
'Set every Property that you need
Me.Controls.Add(TB)
Next
Say If you are having that 30 textboxes inside a panel(PnlTextBoxes), Now you can create handler for your textboxes dynamically like this below
For each ctrl in PnlTextBoxes.controls
If TypeOf ctrl is TextBox then
AddHandler ctrl.TextChanged, AddressOf CommonClickHandler
end if
Next
Private Sub CommonHandler(ByVal sender As System.Object, _
ByVal e As System.EventArgs)
MsgBox(ctype(sender,TextBox).Text)
End Sub
The best way would be to inherit from TextBox, override its OnTextChanged method to add your custom handling code, and then use that on your form(s) instead of the built-in TextBox control.
That way, all of the event handling code is in one single place and you increase abstraction. The behavior follows and is defined within the control class itself, not the form that contains the control. And of course, it frees you from having a bunch of ugly, hard-to-maintain Handles statements, or worse, slow and even uglier For loops.
For example, add this code defining a new custom text box control to a new file in your project:
Public Class CustomTextBox : Inherits TextBox
Protected Overridable Sub OnTextChanged(e As EventArgs)
' Do whatever you want to do here...
MsgBox(Me.Text)
' Call the base class implementation for default behavior.
' (If you don't call this, the TextChanged event will never be raised!)
MyBase.OnTextChanged(e)
End Sub
End Class
Then, after you recompile, you should be able to replace your existing TextBox controls with the newly-defined CustomTextBox control that has all of your behavior built in.

Handle click events from large grid of Buttons?

Okay so I have multitude buttons on a form, and I want a label to display a certain number based on which button is clicked. For example, if any of the buttons in row one of the buttons is clicked, the label would display 10. If any of the buttons from row two are clicked, the label would display 17, etc. How can I do this?
You can use the Handles keyword to handle multiple events, from multiple objects, using one Sub method, for instance:
Private Sub Row1ButtonHandler(ByRef obj As Object, ByRef ea As EventArgs) _
Handles Button1.Click, Button2.Click, Button3.Click
Label1.Text = "1"
End Sub
Private Sub Row2ButtonHandler(ByRef obj As Object, ByRef ea As EventArgs) _
Handles Button4.Click, Button5.Click, Button6.Click
Label1.Text = "17"
End Sub
As you can see, each of those handler methods will now be called any time any of the buttons in their row are clicked.
However, it may be easier to programmatically set-up the event handlers using the AddHandler and RemoveHandler functions:
For c As Int32 = 0 to 10
Dim btn As Control = Page.FindControl("Button" & c)
AddHandler btn.Click, AddressOf MyEventHandler
Next c
Note that I have used a generic Control here and have assumed that you are looking at a webpage, but you could be more specific by using, perhaps, a LinkButton control.
You can use Handles for all button and fetch button in sender value and then add your logic.
May be help you...