How to identify the name of the control when clicked [duplicate] - vb.net

This question already has an answer here:
VB.net dynamic radiobuttons add event onclick
(1 answer)
Closed 5 years ago.
I am adding controls programatically but the problem is I want to show the name of the created controls when clicked.
I can't seem to handle a Control.MouseDown over those created controls when they are programatically created.
Thanks.

That is because, when you add controls in code, you also need to specifically add event handlers to your form for each event you want to handle for that control...
Include code like this where you add the control.
AddHandler MyControl1.MouseDown, AddressOf MyControl_MouseDown
The handler routine MUST follow the same argument structure as the usual event... minus the Handles part.
Private Sub MyControl_MouseDown(sender As Object, e As MouseEventArgs)
' YOUR HANDLING CODE
End Sub
If you REALLY need the name at that point, use the .Name property of the sender object.
Note: You can add the same handler routine to multiple controls if you have common code. If you do, use the Sender object to clarify which control was triggered in the handler.
If you remove a control later, remember to remove the handlers..
RemoveHandler MyControl1.MouseDown
ALTERNATIVE METHOD
If the maximum number of controls you plan on adding is known, then you can add place-holders for them at the top of your form code class...
WithEvents MyControl1 As WhateverItIs
WithEvents MyControl2 As WhateverItIs
WithEvents MyControl3 As WhateverItIs
WithEvents MyControl4 As WhateverItIs
WithEvents MyControl5 As WhateverItIs
WithEvents MyControl6 As WhateverItIs
etc
Note that does not actually create the buttons at that point, they will all be Nothing, but it does tell the compiler what to do with events from those objects when they are assigned to actual objects.
Then assign those when you add the actual control...
Dim NewControl as WhateverItIs
Me.Controls.add NewControl
MyControl1 = NewControl
That way you can add the code for ALL the control's event types for each placeholder if you need them.
Private Sub MyControl1_MouseDown(sender As Object, e As MouseEventArgs) Handles MyControl1.MouseDown
' YOUR HANDLING CODE
End Sub
Private Sub MyControl1_MouseUp(sender As Object, e As MouseEventArgs) Handles MyControl1.MouseUp
' YOUR HANDLING CODE
End Sub
'etc
If you remove a control later remember, to reset the placeholder to nothing..
MyControl1 = Nothing
Unfortunately, you can't make an array or list of WithEvents place-holders.
Note: This is exactly how Visual Studio builds the form designer for you automatically. Each time you add a control through the studio UI, VS adds all that code automatically.

Related

Remove eventhandler dynamically from a control, from another module/class Visual Basic .NET 2010

I have a function defined in a module which updates the passed byref Combobox and Listbox controls.
for simplicity, say that the definition is as under
Module isDB
private sub PopulateCBO(byref CBO as combobox)
'Here I want to remove SelectedValueChanged and click events temporarily removed using
'removehandler or eventhandler.remove
End Sub
End Module
The control maybe on any form from the project.
To remove an event handler you need a reference to an object that raises an event and a delegate for a method that handles that event. You can't arbitrarily clear all handlers for an event. As such, you cannot remove event handlers in the method you've shown. You'd have to pass the event handler in as well, e.g.
Public Sub ConfigureComboBox(comboBox As ComboBox, onSelectedIndexChanged As EventHandler)
'...
RemoveHandler comboBox.SelectedIndexChanged, onSelectedIndexChanged
End Sub
You would then call that in a form like so:
ConfigureComboBox(ComboBox1, AddressOf ComboBoxes_SelectedIndexChanged)
My around turned out to be fairly simple.
I disabled the comboboox with enabled = false and then in the event handler function, I checked if it is enabled =false
Although removing and adding handlers with all their pros and cons didn't even function :)
What I mean is apart of from alternatives, I still wonder who to do that?
The solutions above did not work on my vb 2010.
Private Sub cboProgram_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboProgram.SelectedIndexChanged
If cboProgram.Enabled = True Then
MsgBox("Enabled, so the real event handler")
Else
MsgBox("Disabled, so a false positive")
End If
End Sub

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.

Handle event of a User Control's control in a form

I have a Button in UserControl1.
I am using UserControl1 in Form1.
I want to handle Button's Click event in Form1.
I tried to do same via:
AddHandler userControl1.Button1.Click, AddressOf Button1_Click
And:
Public Sub Button1_Click(ByVal sender As Object, ByVal args As EventArgs) Handles userControl1.Button1.Click
End Sub
but getting error.
Create your event on the UserControl:
Public Class UserControl1
Public Event UC_Button1Click()
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
RaiseEvent UC_Button1Click()
End Sub
End Class
And then use the new event:
AddHandler userControl1.UC_Button1Click, AddressOf Button1_Click
Or you can simply define it like this on the UserControl and access to it from outside (not recommended):
Public WithEvents Button1 As System.Windows.Forms.Button
And then:
AddHandler uc.Button1.Click, AddressOf Button1_Click
I found this very confusing until I placed the "AddHandler" in the main program (not the UserControl).
So for clarification, the steps to ensure that you can "sense" in the main program an event which has occurred in a user control is:
Make sure any object in your user control for which you wish to alter properties (such as PictureBox.Image or TextBox.Text) has its modifier property set to "Public".
This is the only way you can allow other programs to alter properties.
For events which your want recognised (e.g. "Click","DblClick" etc.) place at the top of your User Control code one declaration line for a Public Event. As an example,
Public Event UC_MySub(.....parameters.....)
"UC_" is a prefix I use to help highlight that it is defined in a "UserControl".
The rest of the name ("MySub") can be anything and does not need to relate to the Click Event in any way. You could even call it "CreamedCheese" if you want!
Include any parameters you like the the definition of the public event, again they can be any type of name. These will be passed to the main program when you click on the User Control's object.
Now, Going to the event which runs when you "click" on a GroupBox (in this case), you kick off that public event as shown here:
Private Sub GroupBox_Click(sender As Object, e As EventArgs) Handles GroupBox1.Click
RaiseEvent UC_MySub(....Paramaters.....)
End Sub
You have to ensure the parameters passed in this call to the public event are the same in number (and type) as each of the parameters defined in the Public Event declaration itself.
NOW, you rebuild your User Object, then go to your main program.
In the "Load" routine of your main Form, add the following line FOR EACH OBJECT of the user defined object you are using.
For example, in my program I have 4 instances of my UDO (User Defined Object).
So I have added (assuming my UDO is named "MyUDO"):
AddHandler MyUDO1.UC_MySub, AddressOf SwapHands 'This is my sub accepting the values from the public event
AddHandler MyUDO2.UC_MySub, AddressOf SwapHands
AddHandler MyUDO3.UC_MySub, AddressOf SwapHands
AddHandler MyUDO4.UC_MySub, AddressOf SwapHands
The "SwapHands" routine is defined in my main program and accepts the parameters stored in the UC Public event. The "AddressOf" points your resident subroutine.
The only thing to ensure across all these definitions is that you have the same number of parameters (if you have any) in each case, in the same order, and are of the same type).
(Each parameter can be a different type but must "line up" in types declared in each
definition). (e.g. 1 Boolean, 1 String, another string). In the definitions and calls, there have to be (in this case) 3 parameters of "Boolean, String, String" - in that order.
Now when you run the program and click on the GroupBox (or whatever you have used) in your UDO (User defined object) (on any one of the four objects in this case), you will kick off the routine stored in your main program.
Hard to explain, but after taking HOURS to fathom how this works, I thought I would leave my comments in case others are experiencing the same confusion.

Multiple event handlers for the same event in VB.NET

I've written two event handlers for the TextBox.Leave event for a TextBox1
The reason for this is that the first handler is a common one for multiple TextBox.Leave events which validates the values, and the second one is specific for the above TextBox1 which does some calculation of values.
My query is that can I know which of the two handlers will execute first when TextBox1.Leave happens?
(I know I can remove the code from the common handler to the specific one for TextBox1, but still I wish to know if there is a way.)
Thanks
As long as the event handlers are added using the AddHandler statement, the event handlers are guaranteed to be called in the same order that they were added. If, on the other hand, you are using the Handles modifier on the event handler methods, I don't think there is any way to be sure what the order will be.
Here's a simple example that demonstrates the order as determined by the order in which AddHandler is called:
Public Class FormVb1
Public Class Test
Public Event TestEvent()
Public Sub RaiseTest()
RaiseEvent TestEvent()
End Sub
End Class
Private _myTest As New Test()
Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
AddHandler _myTest.TestEvent, AddressOf Handler1
AddHandler _myTest.TestEvent, AddressOf Handler2
_myTest.RaiseTest()
RemoveHandler _myTest.TestEvent, AddressOf Handler1
RemoveHandler _myTest.TestEvent, AddressOf Handler2
End Sub
Private Sub Handler1()
MessageBox.Show("Called first")
End Sub
Private Sub Handler2()
MessageBox.Show("Called second")
End Sub
End Class
I'd recommend you change to having a single handler, and detect which textbox is being left:
Private Sub txt_Leave(sender As Object, e As System.EventArgs) Handles TextBox1.Leave, TextBox2.Leave
Dim txt As TextBox = DirectCast(sender, TextBox)
If txt Is TextBox1 Then
txt.Text = "Very important textbox!"
Else
txt.Text = "Boring textbox ho hum."
End If
End Sub
This is just additional information not related to the order of execution of multiple event handlers with the same "Handles" clause.
It may be of interest, though, to those wondering about when to use a "Handles" clause and when to use the "AddHandler" statement.
Addhandler is more useful when using a UDC (User Defined Control) to execute procedures/functions or manipulate data within a form.
UDCs know nothing about the form on which they have been attached or referenced.
They are generic and written for reuse in many projects.
Take (for example) the standard "TextBox" control.
Does TextBox know anything about the form on which it rests? No.
All its properties are available to the form but none of the form's properties is available to the Textbox.
(The Textbox is a pre-supplied "UDC", and Microsoft is the User defining it)
If you want your own UDC to operate on data in the main form, you define a public event within the UDC (let's call this event "UC_Update")
It is placed on a single line at the top of the code in the UDC:
Public Event UC_Update ' UC stands for "User Control"
When your UDC (let's call it "MyControl") wants to work with data on its parent form, it can call this event (within the UDC code) with the line:
RaiseEvent UC_Update
Within the code of the form on which this control has been placed or referenced, you attach this event belonging to your UDC to an instance of your control and "point" that event to another routine written in the form.
To do this, you use the "AddHandler" directive and an associated "AddressOf" operator.
Say the process you have written to manipulate data/controls in the form along with data/methods in your UDC, is called "MyControlUpdater".
It will be in your form and look like this:
Private Sub MyControlsUpdater()
......(code).......
end sub
The "(code)" may be lines that use data in your UDC (via public properties or public Subs/Functions) or use data or controls within your form. Your UDC can now do something with items on your form.``
You would place within your form's code the following:
AddHandler MyControl.UC_Update, AddressOf MyControlsUpdater
This directive is placed somewhere after the UDC has been instantiated:
Dim oMyControl as New MyControl
AddHandler oMyControl.UC_Update, AddressOf MyControlsUpdater
If, however, the UDC is physically on your form as "MyControl1", placed there via the Visual Studio Toolbox, then you would add the Handler in your form's "Load" procedure:
Private Sub Form1_Load(sender as object, e as eventargs) Handles Me.Load
AddHandler MyControl1.UC_Update, AddressOf MyControlsUpdater
It is important to note that you cannot pass parameters via this process (when using "AddressOf"). That is why there is no "sender" in the "MyControlsUpdater" subroutine. Values that relate to your UDC
must be obtained by way of public properties in that UDC. Public UDC functions and subroutines (subs) are also available.
If you are NOT working with a UDC (often the case) but with controls created by others such as Microsoft (and therefore the internal code of the control is not available), then you use the "Handles" clause to establish how the control is handled when a certain event arises (such as a "Click" on the control).
Private sub UpdateData(sender as object, e as eventargs) handles Textbox1.Click
........(code)......
End Sub
Of course, if your own UDC doesn't need to know anything about data on your form and you are referencing it rather than adding it physically to the form, you can just use the "Handles" delegation on your own UDC as per normal:
Dim MyControl1 as New MyControl
Private Sub UpdataData(sender as object, e as eventargs) _
handles MyControl1.Text.Leave
Here the form uses data in the control (via public properties) rather than the control using data within the form.

Using events for a dimmed variable

How can I use the event for a dimmed variable that is NOT a control.
This is my dimmed variable:
Dim engine As New Speech.Recognition.SpeechRecognitionEngine
I want to use the event "engine.SpeechRecognized".
You do it the same way you would for anything else where you wanted to add handlers explicitly:
AddHandler engine.SpeechRecognized, AddressOf HandleSpeechRecognized
See the documentation for the AddHandler statement for more information.
There are two ways to add error handlers in VB.NET. You can do so "manually" by using the AddHandler statement, such as:
Dim engine As New SpeechRecognitionEngine()
AddHandler engine.SpeechDetected, AddressOf OnSpeechDetected
With this approach, you would then need to manually implement the OnSpeechDetected event handler method, such as:
Private Sub OnSpeechDetected(ByVal sender As Object, ByVal e As SpeechDetectedEventArgs)
' Do something
End Sub
However, the second method is often easier. This second method is the way that events for controls are handled. However, it is only possible if your object variable is declared as a field (at the class level, outside of any method). All you need to do is add the keyword WithEvents before the variable name, such as:
Dim WithEvents engine As New SpeechRecognitionEngine()
Then, that variable name will show up in the left-side drop-down box at the top of your code window along with all your controls. When you select it in that drop-down box, you can then select any of its events in the right-side drop-down box and it will automatically create the event handler method for you:
Private Sub engine_SpeechDetected(ByVal sender As Object, ByVal e As SpeechDetectedEventArgs) Handles engine.SpeechDetected
End Sub