Handle event of a User Control's control in a form - vb.net

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.

Related

Handles an Event from Control in another class

I want to fire an event in another class.
And my problem is I don't know how to make it.
I'm trying to use Inherits statement to my Form and add my class name to it, and it works as I hope:
Public Class Frm_Main_Copy
Inherits ToolStripMenuApp
'I have a ToolStripMenu that has declared before on my class and it sounds like this:
'Public Shared WithEvents Cat000x86_64App As ToolStripMenuItem
...
Private Sub IsClicked(ByVal sender As Object, ByVal e As EventArgs) Handles Cat000x86_64App.Click
End Sub
End Class
but the designer form messed up(returns a fatal error) and I should delete the Inherits statement, and the others.
Tried to act as form designer script(Trying to put this code to my class):
Friend WithEvents BlahBlah As RadioButton 'For example
It didn't worked,
Declaring a variable for my class and It didn't worked too
Searched on the Internet and it seems likely more complicated than I thought...
Anyone can help? Any help is appreciated.
A form is not a form unless it inherits, either directly or indirectly, the Form class. You cannot inherit any type that is not itself a form and expect your type to be a form. With that code, if ToolStripMenuApp is not a form then Frm_Main_Copy is not a form either, hence no form designer.
If what you're actually saying is that you have an instance of that ToolStripMenuApp that contains a TooStripMenuItem whose Click event you want to handle in Frm_Main_Copy then the first step is to not declare Cat000x86_64App as Shared. Frm_Main_Copy needs to declare a method capable of handling that event:
Private Sub IsClicked(ByVal sender As Object, ByVal e As EventArgs)
'...
End Sub
Note that there is no Handles clause because there's no WithEvents variable in that class whose event you are handling.
Next, Frm_Main_Copy must have access to the appropriate instance of ToolStripMenuApp. It's impossible for us to say how best to do that based on the information provided but it might be as simple as this:
Dim tsma As New ToolStripMenuApp
You then register your method as a handler for the appropriate event:
AddHandler tsma.Cat000x86_64App.Click, AddressOf IsClicked
If you use AddHandler, make sure to use RemoveHandler when you're done with either object. I suggest that you do some reading based on this information.

AddHandlers in VB.NET

I'm trying to dynamically creating dropdownList boxes, and I want trying to add AddHandlers to them so that when an item is selected in them, it fires an event, but also need to pass another variable, and I don't know what to put as the parameter for system.EventArgs. Please look at the code below to see the problem I'm having.
AddHandler inputDrop.SelectedIndexChanged, AddressOf selOption(inputDrop, ???, var1)
Protected Sub selOption(ByVal sender As Object, ByVal e As System.EventArgs, ByVal tableCount As String)
End Sub
What do I put (???) right here.
The error:
is an event, and cannot be called directly. Use a 'RaiseEvent' statement to raise an event.
In addition what Mike C already explained, if the signature of the event handler does not match the event, you can always wrap the event handler in another method, for example an anonymous one:
Protected Sub selOption(ender As Object, e As System.EventArgs, somestring As String)
End Sub
...
For i = 1 To 10
Dim cbox = new ComboBox()
Dim number = i ' local copy to prevent capturing of i '
AddHandler cbox.SelectedIndexChanged, Sub(s, e) selOption(s, e, "Hi! I am Number " & number)
Next
Now, when the index of the last ComboBox changes, the somestring parameter passed to selOption will be Hi! I am Number 10, while it will be Hi! I am Number 1 for the first ComboBox etc.
When you register an event handler, you don't specify the arguments at that time. You're basically just setting a reference to a delegate that will handle the event when it is raised.
AddHandler inputDrop.SelectedIndexChanged, AddressOf selOption
The most important thing is that the method signature of the event handler matches up exactly with the method signature defined by the event. I'm not sure that your method would work because you have that extra tableCount parameter specified. You will need to modify your method signature to be:
Protected Sub selOption(ByVal sender As Object, ByVal e As System.EventArgs)
I'm basing that off the definition of SelectedIndexChanged for Winforms. This event could be defined differently in another technology, such as ASP.net or WPF. Or if this is some custom class, it could be an entirely different signature altogether. However, typically most event handlers have a similar structure of a sender (the instance that raises the event) and some event arguments.
Then when inputDrop fires it's event (when the selected item changes), your code will get automatically called. The arguments passed to this method will be passed directly from inputDrop, you do not have to specify them.
Also, your AddHandler statement must exist inside a method or code block, it can't just live in the class definition. It's a statement that must be executed like any other piece of code, it's not a declaration.
And there is yet another way of doing it. Inherit the control in question and add a property like this:
Public Class MyComboBox : Inherits ComboBox
Public Property tableCount As String
End Class
Then set your custom value and add a handler as you would for a regular ComboBox:
combo.tableCount = tableCount
AddHandler combo.Click, AddressOf combo_Click
Inside combo_Click, CType sender to your inherited type, and get the value you stored previously:
Private Sub combo_Click(sender As Object, e As System.EventArgs)
Debug.WriteLine(CType(sender, WorkflowActionBox).tableCount)
End Sub
You will need to replace current usages of ComboBox with those of MyComboBox, where you want the new property to be available. Simple as opening your designer file and doing find/replace.

AddHandler event on dynamic button, incorrect instance properties in VB.NET

I'm new to custom classes. I have a class called 'game'. In the class, I have a method called 'addGame()' that creates a dynamic picture box called 'pBox'. After creating the control, I'm doing the following to register a click event:
AddHandler pBox.Click, AddressOf Me.launchGame
And here is launchGame:
Public Sub launchGame()
MsgBox(Me.name)
End Sub
The problem is, "Me.name" is always the most recently added instances name, not the one I clicked on.
Based on a suggestion, I also tried this:
Public Sub launchGame(ByVal sender As Object)
MsgBox(sender.name)
End Sub
But now "AddHandler pBox.Click, AddressOf Me.launchGame" says
Method 'Public Sub launchGame(sender As Object)' does not have a signature compatible with delegate 'Delegate Sub EventHandler(sender As Object, e As System.EventArgs)'
And "AddHandler pBox.Click, AddressOf Me.launchGame(Me)" says
AddressOf operand must be the name of a method without parentheses
Public Sub launchGame(ByVal sender As Object, ByVal sender as EventArgs)
MsgBox(sender.name)
End Sub
Now no errors, but the msgBox is blank.
I think the problem was that pBox was always the most recent pictureBox control. I created a control Array based on Creating Control Arrays in Visual Basic .NET and Visual C# .NET (MSDN).
Now I do the AddHandler in the AddNewpBox() method of my pBoxArray class.
I also created a list to handle the "game" class, as suggested by David Brunow. Then I'm setting the pictureBox "Tag" property to the index of the game in the "games" array.
So now my click handler looks like the following, and it seems to work great.
Public Sub pBoxClick(ByVal sender As Object, e As EventArgs)
MsgBox(games(sender.tag).name)
End Sub

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.

How to add event handler to local variable in VB.NET

I have a form in VB.NET that is used as a dialog in a mainform. Its instances are always locally defined, there's no field for it. When the user clicks the OK button in the dialog, it will fire an event with exactly one argument, an instance of one of my classes.
Since it is always a local variable, how can I add an event handler for that event? I've searched for myself and found something but I can't really figure it out...
Code for the event, a field in MyDialog:
public Event ObjectCreated(ByRef newMyObject as MyObject)
Code for the main form to call dialog : (never mind the syntax)
Dim dialog As New MyDialog()
dialog.ShowDialog(Me)
AddHandler ObjectCreated, (what do I put here?) //Or how do I add a handler?
As you can see I'm stuck on how to add a handler for my event. Can anyone help me? Preferrably with the best way to do it...
It's recommended, for consistency, that you use the same source and event args model as all system event handlers.
Create your own class inheriting from EventArgs, as:
Public Class MyObjectEventArgs
Inherits EventArgs
Public Property EventObject As MyObject
End Class
Then declare your event, and a handler method, like:
Public Event ObjectCreated As EventHandler(Of MyObjectEventArgs)
Private Sub Container_ObjectCreated(ByVal sender As Object, ByVal e As MyObjectEventArgs)
' Handler code here
End Sub
Then attach the handler to your event using:
AddHandler ObjectCreated, AddressOf Container_ObjectCreated
Additionally, you can use the Handles to attach to the event raised from your main form (assuming the name MainForm), as below:
Private Sub MainForm_ObjectCreated(ByVal sender As Object, ByVal e As MyObjectEventArgs) Handles MainForm.ObjectCreated
' Handler code here
End Sub
You need to write the subroutine that actually executes when the event is generated:
public Sub OnObjectCreated(ByRef newMyObject as MyObject)
...
End Sub
Then the handler is added:
AddHandler ObjectCreated, AddressOf OnObjectCreated
As a side note, ByRef does nothing here. All objects in VB are passed by reference. Only primitave variables (string, int, etc) by default use ByVal and can be set to ByRef