Need to pass object through dynamically created event handler - vb.net

Need to pass object through dynamically created event handler in vb.net application, (newperson is a usercontrol). The event handler:
AddHandler newperson.MouseUp, AddressOf newperson_MouseUp
Then I use this handler as follows,
Private Sub newperson_MouseUp()
End sub
But I need to refer to the newperson within this sub, e.g.
newperson.Background = Brushes.Black
Any input or ideas will be appreciated :).

You need three things:
A custom EventArgs class where you store a reference to your newPerson object
Public Class MyMouseUpEventArgs
Inherits MouseEventArgs
Public Sub New(newPerson As Person, b As MouseButtons, clicks As Integer, x As Integer, y As Integer, Delta As Integer)
MyBase.New(b, clicks, x, y, Delta)
Me.newPerson = newPerson
End Sub
Public Property newPerson As Person
End Class
It inherits from MouseEventArgs to also have the default event args, but this is not a must have.
In your custom control you need to handle the original MouseUp event. In this handler you simply raise a new custom event which I called MyMouseUp. This custom event takes as parameter the previously created MyMouseEventArgs with the new person
Public Class Person
Inherits UserControl
Public Shared Event MyMouseUp(sender As Object, e As MyMouseUpEventArgs)
Public Sub New()
AddHandler Me.MouseUp, AddressOf OnMouseUp
End Sub
Private Overloads Sub OnMouseUp(sender As Object, e As MouseEventArgs)
RaiseEvent MyMouseUp(sender, New MyMouseUpEventArgs(Me, e.Button, e.Clicks, e.X, e.Y, e.Delta))
End Sub
End Class
The custom event must be shared so it can be used in the handler class without object reference shown in step
The handler (here just the main form) now registers to the new custom event with the custom event args. Thus you can access newPerson.
Public Class Form1
Public Sub New()
InitializeComponent()
AddHandler Person.MyMouseUp, AddressOf OnyMyMouseUp
End Sub
Private Overloads Sub OnyMyMouseUp(sender As Object, e As MyMouseUpEventArgs)
'Do stuff
e.newPerson.BackColor = Color.Aqua
End Sub
End Class
Hope that helps. The code is not tested so no warranty is given ;)

Related

Getting Event Handler from Instance of Class

I'm just getting started with custom classes so I wrote a button strip. It inherits a panel and populates it with buttons from strings passed to my .Add().
ButtonStrip1.Add("Button","Texts","Go Here")
I'd like for it to be able to naturally grab ButtonStrip1.Click's handler and pass it on to child buttons and delete it from ButtonStrip1.
I haven't been able to figure that out, so I've been doing
Public Class ButtonStrip
Inherits Panel
Public Property Innermargin As Integer = 5
Dim Offset As Integer = Innermargin
Dim Buttons = New List(Of ButtonStrip_Button)
Dim StoredFN As EventHandler
Public Sub New()
End Sub
Function Add(fn As EventHandler, ParamArray ByVal Values As String())
StoredFN = fn
For Each V In Values
Dim B As New ButtonStrip_Button
Buttons.Add(B)
Me.Controls.Add(B)
B.Text = V
B.Left = Offset + Innermargin
B.Top = Innermargin
Offset = B.Left + B.Width
AddHandler B.Click, fn
Next
RemoveHandler Me.Click, fn
Me.Width = Offset + Innermargin
Me.Height = Buttons(0).height + Innermargin * 2
End Function
Function Add(ParamArray ByVal Values As String())
If StoredFN Is Nothing Then
Throw New Exception("First Add() must supply a function")
End If
Me.Add(StoredFN, Values)
End Function
End Class
Public Class ButtonStrip_Button
Inherits System.Windows.Forms.Button
Public Sub New()
AutoSize = True
AutoSizeMode = AutoSizeMode.GrowAndShrink
End Sub
End Class
which is called by
ButtonStrip1.Add(AddressOf ButtonStrip1_Click,"Button","Texts","Go Here")
What I'd basically like to do is (psuedo-code)
Function Add(fn As EventHandler, ParamArray ByVal Values As String())
If StoredFN is Nothing Then StoredFN = Me.Click
...
AddHandler B.Click, Me.Click
Next
RemoveHandler Me.Click, Me.Click
...
End Function
I've tried changing a few things and googled a lot. I've also tried using CallByName(Me,"Click",CallType.Method) and with CallType.Get, but the error I get is Expression 'Click' is not a procedure, but occurs as the target of a procedure call. It also returns this exact same message for unhandled events, such as ButtonStrip1 has no MouseDown Event.
I've also tried using MyClass.
Not seen here is an alternative .Add() that add StoredFN to B.click
For instance, this click event works with my code
Private Sub ButtonStrip1_Click(sender As Object, e As EventArgs) Handles ButtonStrip1.Click
msgbox("You clicked " & sender.text & ".")
End Sub
What I was suggesting was something like this:
Public Class ButtonStrip
Inherits Panel
Public Event ButtonClick As EventHandler(Of ButtonClickEventArgs)
Protected Overridable Sub OnButtonClick(e As ButtonClickEventArgs)
RaiseEvent ButtonClick(Me, e)
End Sub
Private Sub Buttons_Click(sender As Object, e As EventArgs)
OnButtonClick(New ButtonClickEventArgs(DirectCast(sender, Button)))
End Sub
Public Sub Add(ParamArray values As String())
Dim btn As New Button
AddHandler btn.Click, AddressOf Buttons_Click
'...
End Sub
End Class
Public Class ButtonClickEventArgs
Inherits EventArgs
Public ReadOnly Property Button As Button
Public Sub New(button As Button)
Me.Button = button
End Sub
End Class
Now there's no need to pass event handlers around. When a Button is clicked, the ButtonStrip handles that event and then raises its own ButtonClick event. Neither the ButtonStrip nor the Buttons have to care about any methods that handle that event as it will be handled the same way any other event is. In a form, you'd then handle the ButtonClick event of the ButtonStrip and get the Button that was clicked from e.Button. You could also add an Index property if you wanted to know the position of the Button rather than the Button itself.

Safe ThreadPool Queueing with Parameters in VB.NET (WinForms)

I know how to use BackgroundWorker (gui object in WinForms designer), and to manually instantiate Threads that elevate the custom event to the UI, however, I am having some trouble figuring out how to use the ThreadPool object (simplest form) to handle elevating an event to the form for "safe" UI manipulation.
Example is as follows :
Form1.vb
Public Class Form1
WithEvents t As Tools = New Tools
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
t.Unzip("file 1", "foo")
t.Unzip("file 2", "foo")
t.Unzip("file 3", "foo")
t.Unzip("file 4", "foo")
t.Unzip("file 5", "foo")
t.Unzip("file 6", "foo")
t.Unzip("file 7", "foo")
t.Unzip("file 8", "foo")
t.Unzip("file 9", "foo")
End Sub
Private Sub t_UnzipComplete(ZipInfo As Tools.ZipInfo) Handles t.UnzipComplete
TextBox1.Text = TextBox1.Text & ZipInfo.ZipFile & vbCr
End Sub
End Class
( add a multiline textbox, and a button to this form for the demo )
Tools.vb
Imports System
Imports System.Threading
Imports System.IO.Compression
Public Class Tools
#Region "Zip"
Private _zip As System.IO.Compression.ZipFile
Public Shared Event UnzipComplete(ByVal ZipInfo As ZipInfo)
Public Shared Event ZipComplete(ByVal ZipInfo As ZipInfo)
Public Class ZipInfo
Public Property ZipFile As String
Public Property Path As String
End Class
Public Sub Unzip(ByVal ZipFile As String, ByVal Destination As String)
Dim _ZipInfo As New Tools.ZipInfo
_ZipInfo.ZipFile = ZipFile
_ZipInfo.Path = Destination
ThreadPool.QueueUserWorkItem(AddressOf ThreadUnzip, _ZipInfo)
End Sub
Public Sub Zip(ByVal Folder As String, ByVal ZipFile As String)
Dim _ZipInfo As New Tools.ZipInfo
_ZipInfo.ZipFile = ZipFile
_ZipInfo.Path = Folder
ThreadPool.QueueUserWorkItem(AddressOf ThreadUnzip, _ZipInfo)
End Sub
Shared Sub ThreadUnzip(ZipInfo As Object)
RaiseEvent UnzipComplete(ZipInfo)
End Sub
Shared Sub ThreadZip(ZipInfo As Object)
RaiseEvent ZipComplete(ZipInfo)
End Sub
#End Region
End Class
What this code should do, is as follows :
On Button1_Click, add 9 items to the ThreadPool
On each thread completion (order is irrelevant), raise an event that elevates to Form1
The event being raised on Form1 should be UI safe, so I can use the information being passed to the ZipCompleted / UnzipCompleted events in the Textbox. This should be generic, meaning the function that raises the event should be reusable and does not make calls to the form directly. (aka, I do not want a "custom" sub or function in Tools.vb that calls specific elements on Form1.vb . This should be generic and reusable by adding the class to my project and then entering any "custom" form code under the event being raised (like when Button1_Click is raised, even though it's threaded, the other form interactions are not part of the Button1 object/class -- they are written by the coder to the event that is raised when a user clicks.
If you want to ensure that an object that has no direct knowledge of your UI raises its events on the UI thread then use the SynchronizationContext class, e.g.
Public Class SomeClass
Private threadingContext As SynchronizationContext = SynchronizationContext.Current
Public Event SomethingHappened As EventHandler
Protected Overridable Sub OnSomethingHappened(e As EventArgs)
RaiseEvent SomethingHappened(Me, e)
End Sub
Private Sub RaiseSomethingHappened()
If Me.threadingContext IsNot Nothing Then
Me.threadingContext.Post(Sub(e) Me.OnSomethingHappened(DirectCast(e, EventArgs)), EventArgs.Empty)
Else
Me.OnSomethingHappened(EventArgs.Empty)
End If
End Sub
End Class
As long as you create your instance of that class on the UI thread, its SomethingHappened event will be raised on the UI thread. If there is no UI thread then the event will simply be raised on the current thread.
Here's a more complete example, which includes a simpler method for using a Lambda Expression:
Imports System.Threading
Public Class Form1
Private WithEvents thing As New SomeClass
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.thing.DoSomethingAsync()
End Sub
Private Sub thing_DoSomethingCompleted(sender As Object, e As IntegerEventArgs) Handles thing.DoSomethingCompleted
MessageBox.Show(String.Format("The number is {0}.", e.Number))
End Sub
End Class
''' <summary>
''' Raises events on the UI thread after asynchronous tasks, assuming the instance was created on a UI thread.
''' </summary>
Public Class SomeClass
Private ReadOnly threadingContext As SynchronizationContext = SynchronizationContext.Current
Public Event DoSomethingCompleted As EventHandler(Of IntegerEventArgs)
''' <summary>
''' Begin an asynchronous task.
''' </summary>
Public Sub DoSomethingAsync()
Dim t As New Thread(AddressOf DoSomething)
t.Start()
End Sub
Protected Overridable Sub OnDoSomethingCompleted(e As IntegerEventArgs)
RaiseEvent DoSomethingCompleted(Me, e)
End Sub
Private Sub DoSomething()
Dim rng As New Random
Dim number = rng.Next(5000, 10000)
'Do some work.
Thread.Sleep(number)
Dim e As New IntegerEventArgs With {.Number = number}
'Raise the DoSomethingCompleted event on the UI thread.
Me.threadingContext.Post(Sub() OnDoSomethingCompleted(e), Nothing)
End Sub
End Class
Public Class IntegerEventArgs
Inherits EventArgs
Public Property Number() As Integer
End Class
You should register from the Form to events of the Tools class (you already have these events defined), of course the actual event will be fired under a non-UI thread, so the code it executes during the callback will only be able to update the UI via an Invoke()
You want to simply raise the event in the Tools class, the Invoke needs to be done because you want to update the UI, the Tools class should be concerned about that.
Change your event handling like so:
Private Sub t_UnzipComplete(ZipInfo As Tools.ZipInfo) Handles t.UnzipComplete
TextBox1.Invoke(Sub () t_UnzipComplete(ZipInfo))
End Sub
To register to the event from the view: (this would go in the Button1_Click event
AddHandler t.UnzipComplete, AddressOf t_UnzipComplete
Make sure you only register to the event one time
Does this solve your issue?
Private Sub t_UnzipComplete(ZipInfo As Tools.ZipInfo) Handles t.UnzipComplete
If TextBox1.InvokeRequired Then
TextBox1.Invoke(Sub () t_UnzipComplete(ZipInfo))
Else
TextBox1.Text = TextBox1.Text & ZipInfo.ZipFile & vbCr
End If
End Sub
You could create a callback to do the invoking in a safer way. Something like this:
Public Sub Unzip(ByVal ZipFile As String, ByVal Destination As String, _
ByVal SafeCallback As Action(Of ZipInfo))
And then the calling code does this:
t.Unzip("file 1", "foo", Sub (zi) TextBox1.Invoke(Sub () t_UnzipComplete(zi)))
Personally I think it is better - and more conventional - to invoke on the event handler, but you could do it this way.
Okay, so here is what I came up with using a combination of the information from everyone contributing to this question -- all excellent and VERY helpful answers, which helped lead me to the final solution. Ideally, I would like this as a straight "class", but I can accept a UserControl for this purpose. If someone can take this and do exactly the same thing with a class, that would definitely win my vote. Right now, I will really have to consider which one to vote for.
Here is the updated Tools.vb
Imports System
Imports System.Threading
Imports System.Windows.Forms
Imports System.IO.Compression
Public Class Tools
Inherits UserControl
#Region "Zip"
Private _zip As System.IO.Compression.ZipFile
Private threadingContext As SynchronizationContext = SynchronizationContext.Current
Private Delegate Sub EventArgsDelegate(ByVal e As ZipInfo)
Public Shared Event UnzipComplete(ByVal ZipInfo As ZipInfo)
Public Shared Event ZipComplete(ByVal ZipInfo As ZipInfo)
Public Class ZipInfo
Public Property ZipFile As String
Public Property Path As String
End Class
Public Sub Unzip(ByVal ZipFile As String, ByVal Destination As String)
Dim _ZipInfo As New Tools.ZipInfo
_ZipInfo.ZipFile = ZipFile
_ZipInfo.Path = Destination
ThreadPool.QueueUserWorkItem(AddressOf ThreadUnzip, _ZipInfo)
End Sub
Public Sub Zip(ByVal Folder As String, ByVal ZipFile As String)
Dim _ZipInfo As New Tools.ZipInfo
_ZipInfo.ZipFile = ZipFile
_ZipInfo.Path = Folder
ThreadPool.QueueUserWorkItem(AddressOf ThreadUnzip, _ZipInfo)
End Sub
Private Sub ThreadUnzip(ZipInfo As Object)
If Me.InvokeRequired Then
Me.Invoke(New EventArgsDelegate(AddressOf ThreadUnzip), ZipInfo)
Else
RaiseEvent UnzipComplete(ZipInfo)
End If
End Sub
Private Sub ThreadZip(ZipInfo As Object)
If Me.InvokeRequired Then
Me.Invoke(New EventArgsDelegate(AddressOf ThreadZip), ZipInfo)
Else
RaiseEvent ZipComplete(ZipInfo)
End If
End Sub
#End Region
End Class
If you drop this on Form1.vb, and select/activate the UnzipComplete/ZipComplete events, you will find that they will interact with the UI thread without having to pass a Sub, or Invoke, etc, from the Form. It is also generic, meaning it is unaware of what form elements you will be interacting with so explicit invoking such as TexBox1.Invoke() or other element specific calls are not required.

Events in a VB.Net multi-project solution

Is it possible, to raise a global event in a multiproject solution in VB.Net. For example, project 1 has a form called Form1. On Form1 there is a button, that when clicked, raises an event, where project2 can handle that event, and even project3 could handle that event.
You can have a dedicated Project that has a Class whose sole purpose is to house a "Global Event". Make that Class implement the Singleton Pattern so that all the projects will access the same instance. All the other projects can Reference this Project and could look like this:
' This is in Project3
Public Class Class1
Private Sub New()
End Sub
Private Shared _Instance As Class1
Public Event GlobalEvent()
Public Shared ReadOnly Property Instance As Class1
Get
If IsNothing(_Instance) Then
_Instance = New Class1
End If
Return _Instance
End Get
End Property
Public Sub RingTheBell()
RaiseEvent GlobalEvent()
End Sub
End Class
Here is FormA in Project1, displaying FormB in Project2 (Project1 has a reference to both Project2 and Project3). We grab the singleton instance and call the RingTheBell() method to raise the "Global Event":
' This is in Project1
Public Class FormA
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim frmB As New Project2.FormB
frmB.Show()
End Sub
Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
Project3.Class1.Instance.RingTheBell()
End Sub
End Class
Finally, over in Project2, we also grab the singleton instance and subscribe to its GlobalEvent (Project2 only has a reference to Project3):
' This is in Project2
Public Class FormB
Private WithEvents x As Project3.Class1 = Project3.Class1.Instance
Private Sub x_GlobalEvent() Handles x.GlobalEvent
MessageBox.Show("GlobalEvent() trapped in Project2")
End Sub
End Class
So any Project that wants to subscribe to the "Global Event" simply adds a Reference to Project3 and uses the Instance() method which returns the singleton instance to which that Project can subscribe to the event with.
This is possible via a number of possible routes. I'd prefer dependency injection in this case.
First, create your global event owner project. I named mine GlobalEventSample. I removed the default namespace and declared it here explicitly to make the code structure more obvious:
Namespace GlobalEventSample
Public Module Module1
Public Event GlobalEvent As EventHandler
Public Sub Main()
Console.WriteLine("Press any key to raise event...")
Console.ReadKey(True)
RaiseEvent GlobalEvent(Nothing, EventArgs.Empty)
Console.WriteLine("Press any key to quit...")
Console.ReadKey(True)
End Sub
End Module
End Namespace
Now create the consumer project. I named mine GlobalEventConsumer. I removed the default namespace and declared it here explicitly (just as above):
Namespace GlobalEventConsumer
Public Interface IGlobalEventOwner
Event GlobalEvent As EventHandler
End Interface
Public Class Class1
Public Sub New(ByVal globalEvent As IGlobalEventOwner)
AddHandler globalEvent.GlobalEvent, AddressOf GlobalEventHandler
End Sub
Public Shared Sub GlobalEventHandler(ByVal sender As Object, ByVal e As EventArgs)
Console.WriteLine("Event Handled!")
End Sub
End Class
End Namespace
Notice that I've declared an interface named "IGlobalEventOwner". All it does is define an object with an event. This event has a signature identical to the global event we want to handle.
Go back to the sample project and create a reference to the consumer project.
The consumer project requires an object which implements IGlobalEventOwner. Modules cannot implement interfaces, so we instead create a private class, GlobalEventRouter, which will simply handle the module's event and then fire its own event. Finally, we will create a new instance of Class 1 in the Main sub and pass an instance of the GlobalEventRouter class.
Namespace GlobalEventSample
Public Module Module1
Public Event GlobalEvent As EventHandler
Public Sub Main()
Dim consumer As New GlobalEventConsumer.Class1(New GlobalEventRouter())
Console.WriteLine("Press any key to raise event...")
Console.ReadKey(True)
RaiseEvent GlobalEvent(Nothing, EventArgs.Empty)
Console.WriteLine("Press any key to quit...")
Console.ReadKey(True)
End Sub
Private Class GlobalEventRouter
Implements GlobalEventConsumer.IGlobalEventOwner
Public Event GlobalEvent(ByVal sender As Object, ByVal e As System.EventArgs) Implements GlobalEventConsumer.IGlobalEventOwner.GlobalEvent
Public Sub New()
AddHandler Module1.GlobalEvent, AddressOf GlobalEventHandler
End Sub
Private Sub GlobalEventHandler(ByVal sender As Object, ByVal e As EventArgs)
RaiseEvent GlobalEvent(sender, e)
End Sub
End Class
End Module
End Namespace
The output:
Press any key to raise event...
Event Handled!
Press any key to quit...

How to Pass Additional Parameters When Calling and Event VB.net

Public Event DocumentCompleted As WebBrowserDocumentCompletedEventHandler
Dim arg() As Object = {homeTeam, guestTeam}
AddHandler browser.DocumentCompleted, New
WebBrowserDocumentCompletedEventHandler(AddressOf DoStuff)
Private Sub DoStuff(ByVal sender As Object, ByVal e As WebBrowserDocumentCompletedEventArgs)
End Sub
How can I pass the homeTeam and guestTeam when firing the DocumentCompleted event.
I want to ge the above to values to inside the Dostuff method.
Please help.
First of all, you cannot have this hanging in the middle of nowhere:
Dim arg() As Object = {homeTeam, guestTeam}
AddHandler browser.DocumentCompleted,
New WebBrowserDocumentCompletedEventHandler(AddressOf DoStuff)
AddHandler probably needs to be in some Initialize method, which could be inside Sub New, after InitializeComponent, or inside Form_Load, or as soon as you expect it to be triggered (after a specific event). Notice here that you are using a default event of a native .NET component, with a default event type. In this case you cannot directly consume anything other than what it already provides, when triggered. See WebBrowser.DocumentCompleted Event on MSDN.
You can, however, override all relevant classes and have your own MyWebBrowser control and your own event, with would contain additional properties. See below example:
Public Class Form1
Sub New()
' This call is required by the designer.
InitializeComponent()
Dim browser As New MyWebBrowser
AddHandler browser.MyDocumentCompleted, AddressOf DoStuff
End Sub
Private Sub DoStuff(ByVal sender As Object, ByVal e As MyWebBrowserDocumentCompletedArgs)
Dim guestTeam As String = e.GuestTeam 'guest team
Dim homeTeam As String = e.HomeTeam 'and home team are both accessible
'so you can do some processing on them
End Sub
Public Class MyWebBrowserDocumentCompletedArgs : Inherits WebBrowserDocumentCompletedEventArgs
Dim _homeTeam As String
Dim _guestTeam As String
Public ReadOnly Property HomeTeam
Get
Return _homeTeam
End Get
End Property
Public ReadOnly Property GuestTeam
Get
Return _guestTeam
End Get
End Property
Sub New(url As Uri, homeTeam As String, guestTeam As String)
MyBase.New(url)
_homeTeam = homeTeam
_guestTeam = guestTeam
End Sub
End Class
Public Class MyWebBrowser : Inherits WebBrowser
Public Delegate Sub MyWebBrowserDocumentCompletedEventHandler(e As MyWebBrowserDocumentCompletedArgs)
Public Event MyDocumentCompleted As MyWebBrowserDocumentCompletedEventHandler
Protected Overrides Sub OnDocumentCompleted(e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs)
MyBase.OnDocumentCompleted(e)
'homeTeam and guestTeam need to be extracted from the current instance of MyWebBrowser, and passed further
RaiseEvent MyDocumentCompleted(New MyWebBrowserDocumentCompletedArgs(e.Url, "homeTeam", "guestTeam"))
End Sub
End Class
End Class
If your project is relatively small, you can indeed have those as global variables, as #Vlad suggested in the comments.

Event Handling an Abstract Class

Basically, I have a custom child form class which has events that will be passed to the parent. In the custom child form, I have a declaration of a "MustInherit" class that inherits the DevExpress User Control Class.
The reason for this, is I have many user controls that derive from this base class, and the child form can have an instance of any one of these controls, and doesnt care which. The only requirement is that the child form can handle the same events from each type of control the same way.
Some watered down code snippets(still pretty long unfortunately):
'''Inherited Class
Public Class ChildControlInheritedClass
'A Button Click event that starts the chain of events.
Private Sub btnMoveDocker_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConvertToTab.Click
OnMoveToDocker(Me, New ChildGridMoveArgs(Me))
End Sub
End Class
'''Base Class
Public MustInherit Class ChildControlBaseClass
Inherits DevExpress.XtraEditors.XtraUserControl
Public Class ChildGridMoveArgs
Inherits System.EventArgs
Public Sub New(ByVal _ChildControl As ChildControlInheritedClass)
ChildControl = _ChildControl
End Sub
Public ChildControl As ChildControlInheritedClass
End Class
Public Event MoveToDocker(ByVal sender As Object, ByVal e As ChildGridMoveArgs)
Protected Overridable Sub OnMoveToDocker(ByVal sender As Object, ByVal e As ChildGridMoveArgs)
'''Once this RaiseEvent is fired, nothing happens. The child form is oblivious.
RaiseEvent MoveToDocker(sender, e)
End Sub
End Class
'''Child Form Class
Public Class ChildForm
Private WithEvents cgChild As ChildControlBaseClass
Public Property ChildGrid() As ChildControlInheritedClass
Get
Return cgChild
End Get
Set(ByVal value As ChildControlInheritedClass)
RemoveHandler cgChild.MoveToDocker, AddressOf cgChild_MoveToDocker
cgChild.Dispose()
cgChild = Nothing
cgChild = value
AddHandler cgChild.MoveToDocker, AddressOf cgChild_MoveToDocker
End Set
End Property
Public Event MoveToDocker(ByVal sender As Object, ByVal e As ChildControlInheritedClass.ChildGridMoveArgs)
Public Sub cgChild_MoveToDocker(ByVal sender As Object, ByVal e As ChildControlInheritedClass.ChildGridMoveArgs)
RaiseEvent MoveToDocker(sender, New ChildControlInheritedClass.ChildGridMoveArgs(cgChild))
End Sub
End Class
Public Class frmMain
Private Sub OpenNewWindow()
Dim frm As New ChildForm
Dim chld As New ChildControlInheritedClass
frm.ChildGrid = chld
frm.Show()
End Sub
End Class
In a nutshell, thats how I made the child form and how everything is suppose to work. But when I press the button in the inherited child control, the event only gets as far as the base class and never traverses the RaiseEvent into the child form thats suppose to handle the event.
Am I even in the ballpark here?
Thanks for reading!
You forgot to add your event handle by using AddHandler or Handles identifier. See below using the Handles cgChild.MoveToDocker identifier.
Public Class ChildForm
...
Public Sub cgChild_MoveToDocker(ByVal sender As Object, ByVal e As ChildControlInheritedClass.ChildGridMoveArgs) Handles cgChild.MoveToDocker
RaiseEvent MoveToDocker(sender, New ChildControlInheritedClass.ChildGridMoveArgs(cgChild))
End Sub
End Class