First of all, this is my very first question in this community. Please give me some advice if I did it in the wrong way.
I need a little bit help. I am actually working on a BMEcat class library, BMEcat is a data exchange format for electronic catalogs. Anything works fine, but I realized that there is a memory problem while processing very large files. Because of this, I want to send an event for any processed article/product instead of creating a huge structure in memory.
This is the point where my problem begins.
I have a class CTRANSACTION, from which the classes CT_NEW_CATALOG, CT_UPDATE_PRODUCTS and CT_UPDATE_PRICES are derived.
In the base class CTRANSACTION there is an event defined:
Public Event Transaction_OnNewArticle(ByVal sender As Object, ByVal e As ArticleEventArgs)
The class CBMECAT has the variable
Public WithEvents TRANSACTION As CTRANSACTION
and the event handler
Private Sub TRANSACTION_Transaction_OnNewArticle(sender As Object, e As ArticleEventArgs) Handles TRANSACTION.Transaction_OnNewArticle
'...
End Sub
Because I cannot send the event Transaction_OnNewArticle from the derived CT_NEW_CATALOG class I let it call the TransactionEventOnNewArticle method instead, which is defined in CTRANSACTION. TransactionEventOnNewArticle then calls RaiseEvent Transaction_OnNewArticle.
Everything works wonderful, but the event Transaction_OnNewArticle is not fired. Is there a way to fix it?
Public MustInherit Class CTRANSACTION
Inherits CBMECAT_NODE
Public Event Transaction_OnNewArticle(ByVal sender As Object, ByVal e As ArticleEventArgs)
Public Sub TransactionEventOnNewArticle(ByVal sender As Object, ByVal e As ArticleEventArgs)
RaiseEvent Transaction_OnNewArticle(sender, e)
End Sub
Public Class CT_NEW_CATALOG
Inherits CTRANSACTION
Public Overrides Sub EventOnNewArticle(ByVal sender As Object, ByVal e As ArticleEventArgs)
TransactionEventOnNewArticle(sender, e)
End Sub
Public Class CBMECAT
Inherits CBMECAT_NODE
Public WithEvents TRANSACTION As CTRANSACTION
Private Sub TRANSACTION_Transaction_OnNewArticle(sender As Object, e As ArticleEventArgs) Handles TRANSACTION.Transaction_OnNewArticle
'THIS method is never called - why?
End Sub
End Class
UPDATE
Public Class CBMECAT_ELEMENT
Public Overridable Sub EventOnNewArticle(ByVal sender As Object, ByVal e As ArticleEventArgs)
End Sub
'Please notice that CBMECAT_ELEMENT is the base class of EVERY other class in the library.
'There is a class CBMECAT_NODE, which represents every node of the BMEcat XML structure and is derived from CBMECAT_ELEMENT.
'In CBMECAT_NODE is EventOnNewArticle called whenever an article is processed;
Public Class CBMECAT_NODE
Inherits CBMECAT_ELEMENT
Public Overridable Function CreateChildNode(ByRef Nodename As String, Optional ByRef Parent As CBMECAT_NODE = Nothing) As CBMECAT_ELEMENT
Select Case Nodename
[..]
Case ELEMENT_ARTICLE
CreateChildNode = New CARTICLE(Parent)
Dim e As New ArticleEventArgs With
{
.ARTICLE = CreateChildNode
}
EventOnNewArticle(Me, e)
[..]
UPDATE
Public Class CARTICLE
Inherits CBMECAT_NODE
Public Sub New(ByRef Father As CBMECAT_NODE)
[..]
Public Overrides Sub Read()
[..]
Public Overrides Sub Write()
[..]
Public Overrides Sub Validate()
[..]
UPDATE
Calling sequence:
CBMECAT_NODE.CreateChildNode calls CT_NEW_CATALOG.EventOnNewArticle <- OK
CT_NEW_CATALOG.EventOnNewArticle calls CTRANSACTION.TransactionEventOnNewArticle <- OK
CTRANSACTION.TransactionEventOnNewArticle fires Event Transaction_OnNewArticle
but this event is not received by the event handlier in CBMECAT
If I fire the event manually from a method in CTRANSACTION the event IS received by the event handler.
I also experimentet with AddHandler/RemoveHandler, but this also did not work.
Thank you, Visual Vincent, for helping me to focus the problem and to solve it. In deed it was "a little bit" complicated.
Class CBMECAT had the following read method:
Public Overrides Sub Read()
MyBase.Read()
GetContent(HEADER, ELEMENT_HEADER)
Select Case TransactionType
Case TransactionTypes.T_NEW_CATALOG
GetContent(TRANSACTION, ELEMENT_T_NEW_CATALOG)
Case TransactionTypes.T_UPDATE_PRICES
GetContent(TRANSACTION, ELEMENT_T_UPDATE_PRICES)
Case TransactionTypes.T_UPDATE_PRODUCTS
GetContent(TRANSACTION, ELEMENT_T_UPDATE_PRODUCTS)
Case Else
ReportError(ERROR_BMECAT_UNKNOWN_TRANSACTION_TYPE)
End Select
Validate()
End Sub
MyBase.Read reads the complete XML file and while reading it, the events should be fired. But at this moment the variable TRANSACTION is not assigned by it´s value. This is done by calling GetContent after the reading process has finished.
I have changed to:
TRANSACTION = New CT_NEW_CATALOG
TRANSACTION.Read()
Now all events are fired as expected.
I will remove TransactionEventOnNewArticle() from CBMECAT_ELEMENT. Thanks again, Vincent, for your suggestion. :-)
Related
Hoping to get some best-practice advise with regards to capturing a returned message from an instantiated class on my form.
In my form (form1.vb), I have a label which reflects what is being done, with the code below.
Code in form1.vb to display message:
Public Sub DisplayMessage(ByVal Msg as String, ByVal Show as Boolean)
Application.DoEvents()
If Show Then
lblShow.Text = Msg
lblShow.Refresh()
End If
End Sub
I have came across three methods so far:
Direct Form Call. In this scenario the class directly calls the form's message routine:
form1.DisplayMessage("Show This Message", True)
RaiseEvent within class. In this scenario form1 is Friends WithEvents of the class sending the message, and the class raises the event to the form.
**Declared in Form1.vb**
Friend WithEvents Class1 as New Class1
**Declared in Class1.vb**
Public Event SetMessage(ByVal Msg As String, ByVal Show As Boolean)
**Used in Class1.vb**
RaiseEvent SetMessage("Show This Message", True)
Have an EventArgs class handle the event. In this scenario we have an EventArg.vb class which is instantiated whenever we raise the event.
**Declared in Form1.vb**
Friend WithEvents Class1 as New Class1
Private Sub class1_DisplayMessage(ByVal Msg As String, ByVal showAs Boolean, ByRef e As ProgressMessageEventArgs) Handles Class1.SetMessage
DisplayMessage(Msg, Show)
End Sub
**Declared in Class1.vb**
Public Event SetMessage(ByVal msg As String, ByVal Show As Boolean, ByRef e As ProgressMessageEventArgs)
Protected Sub CaptureMessage(ByVal msg As String, ByVal Show As Boolean)
RaiseEvent SetMessage(message, ShowList, New ProgressMessageEventArgs(message))
End Sub
**Used in Class1.vb**
RaiseEvent CaptureMessage("Show This Message", True)
**EventArg.vb created to handle ProgressMessageEventArgs class**
Public NotInheritable Class ProgressMessageEventArgs
Inherits System.EventArgs
Public txt As String
Public Sub New(ByVal txt As String)
MyBase.New()
Me.Text = txt
End Sub
End Class
Scenario 1 is seemingly the simplest, though I was advised against this and asked to raise an event instead. Over time I came across scenario 3 which involves an additional class vs scenario 2.
Therefore, the question is...
Between these three methods, which would be the "proper" way of returning a message from a class to the form? Is the additional EventArg class as per scenario 3 necessary since scenario 2 works fine as well?
Many thanks in advance.
My answer is none of the above. Consider this example
Public Class Form1
Private WithEvents myClass1 As New Class1()
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
myClass1.CountTo1000()
End Sub
Private Sub MyClass1_Updated(number As Integer) Handles myClass1.Updated
Me.Label1.Text = number.ToString()
End Sub
End Class
Public Class Class1
Public Event Updated(number As Integer)
Public Sub CountTo1000()
For i = 1 To 1000
System.Threading.Thread.Sleep(1)
RaiseEvent Updated(i)
Next
End Sub
End Class
You have a form and a class, and the form has a reference to the class (the class doesn't even know the form exists). Your business logic is performed in the class, and the form is used to input and display information. CountTo1000() is being called directly from the form, which is bad because basically the UI thread is being put to sleep 1000 times, while the class is trying to update the UI by raising the event after each sleep. But the UI never has time to allow the events to happen, i.e. to be updated. Placing an Application.DoEvents() after Me.Label1.Text = number.ToString() will allow the UI to update. But this is a symptom of bad design. Don't do that.
Here is another example with multi-threading
Public Class Form1
Private WithEvents myClass1 As New Class1()
' this handler runs on UI thread
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' make a new thread which executes CountTo1000
Dim t As New System.Threading.Thread(AddressOf myClass1.CountTo1000)
' thread goes off to do its own thing while the UI thread continues
t.Start()
End Sub
' handle the event
Private Sub MyClass1_Updated(number As Integer) Handles myClass1.Updated
updateLabel(number.ToString())
End Sub
' invoke on UI thread if required
Private Sub updateLabel(message As String)
If Me.Label1.InvokeRequired Then
Me.Label1.Invoke(New Action(Of String)(AddressOf updateLabel), message)
Else
Me.Label1.Text = message
End If
End Sub
End Class
Public Class Class1
Public Event Updated(number As Integer)
Public Sub CountTo1000()
For i = 1 To 1000
System.Threading.Thread.Sleep(1)
RaiseEvent Updated(i)
Next
End Sub
End Class
This simple example shows how a thread can be created and run some code off the UI. When doing this, any method call from the non-UI thread must be invoked on the UI if it must access a UI control (Label1). The program runs smoothly since the Thread.Sleep is done on a different thread than the UI thread, with no need for Application.DoEvents, because the UI thread is otherwise doing nothing, and can handle the events being raised by the other thread.
I focused more on threading, but in both examples the design has a form with a class, and the form knows about the class, but the class doesn't know about the form. More about that can be seen here.
See also:
Why we need to check for InvokeRequired, then invoke: Control.InvokeRequired
A better option than Thread nowadays: BackgroundWorker
An even cooler option, if you can wrap your head around it: Async/Await
I'm new to VB.Net (I'm from a foxpro background) and have had my head in a book for the last two weeks trying to get started with some of the basics.
I'm trying to master class inheritance and have what I hope is not too much of a challenging question.
I've created a class and compiled it as a DLL. It simply allows me to place a button on a form. I just want to capture the Click event - which I've managed to do but would like to override the inherited code rather than having both fire which seems to be happening at the moment.
I realise I could just double click the control and enter code directly into the MyButton1 click event but wanted to trap this programmatically instead via the handler.
I thought this would just be a case of using the overridable / overrides options.
Here's the code in my class:
Imports System.Windows.Forms
Imports System.Drawing
Public Class MyButton
Inherits Windows.Forms.Button
Sub New()
End Sub
Protected Overridable Sub MyButton_Click(sender As Object, e As System.EventArgs) Handles Me.Click
MsgBox("Base Click")
End Sub
End Class
Then I place the button on my form and name it MyButton1 and in the load event:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AddHandler MyButton1.Click, AddressOf Button_Click
End Sub
Private Sub Button_Click()
MsgBox("Actual Click")
End Sub
Problem is, both events fire and I want the option to override / turn off the base event.
I thought I could just add the 'overrides' keyword to the Button_Click routine i.e.:
Private Sub Overrides Button_Click()
but I get an error message Sub Button_Click() cannot be declared 'overrides' because it does not override a sub in a base class
So to clarify - at the moment my code fires both events so I get two messages. I want to be able to turn off / supress the base class event.
Any help would be much appreciated.
I thought this would just be a case of using the overridable /
overrides options.
The fundamental problem here is that you're trying to push a square peg into a round hole.
To override something, you need to have inheritance involved. The derived class is overriding something that was inherited from the base class. For instance, if you inherited from your MyButton class to create a new type of Button called MyButtonDerived, then you could do it as expected:
Public Class MyButton
Inherits Windows.Forms.Button
Protected Overridable Sub MyButton_Click(sender As Object, e As System.EventArgs) Handles Me.Click
MsgBox("Base Click")
End Sub
End Class
Public Class MyButtonDerived
Inherits MyButton
Protected Overrides Sub MyButton_Click(sender As Object, e As EventArgs)
' We don't call the base method...
' MyBase.MyButton_Click(sender, e)
' ... and instead do something else:
MsgBox("Derived Click")
End Sub
End Class
In contrast, when you've placed MyButton onto the Form as in your original problem description, no inheritance has taken place. Instead what you've setup is "object composition"; the form contains an instance of the button (not derived from it). While it may be possible to change what happens when the button is clicked from the form itself, this is not a case that can be solved with OOP, inheritance and overriding.
If MyButton was not designed in such a way that allows the end user to suppress its base functionality, then your options are limited in how you can use it. Here is an example of what it might look like if MyButton was designed to allow the end user to suppress its base click functionality:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
MyButton1.SuppressDefaultClick = True
End Sub
Private Sub MyButton1_Click(sender As Object, e As EventArgs) Handles MyButton1.Click
MsgBox("Form Click Code")
End Sub
End Class
Public Class MyButton
Inherits Windows.Forms.Button
Private _suppress As Boolean = False
Public Property SuppressDefaultClick As Boolean
Get
Return _suppress
End Get
Set(value As Boolean)
_suppress = value
End Set
End Property
Protected Overridable Sub MyButton_Click(sender As Object, e As System.EventArgs) Handles Me.Click
If Not SuppressDefaultClick Then
MsgBox("Base Click")
End If
End Sub
End Class
If MyButton didn't include a way to suppress its built-in click handler like above then you'd have to resort to other means to solve your problem. In that case you'd have to prevent the button from ever receiving the message that the left mouse button has been clicked at all, and instead implement your own routine. This approach would be a considered a hack, since you are working around the limitations of something and not using it in the way it was originally intended. Here's one way the hack could be implemented:
Public Class Form1
Private WithEvents TMBC As TrapMyButtonClick
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
TMBC = New TrapMyButtonClick(Me.MyButton1)
End Sub
Private Sub TMBC_Click(sender As MyButton) Handles TMBC.Click
MsgBox("Form Click Code")
End Sub
Private Class TrapMyButtonClick
Inherits NativeWindow
Private _mb As MyButton
Private Const WM_LBUTTONDOWN As Integer = &H201
Public Event Click(ByVal sender As MyButton)
Public Sub New(ByVal mb As MyButton)
If Not IsNothing(mb) AndAlso mb.IsHandleCreated Then
_mb = mb
Me.AssignHandle(mb.Handle)
End If
End Sub
Protected Overrides Sub WndProc(ByRef m As Message)
Select Case m.Msg
Case WM_LBUTTONDOWN
RaiseEvent Click(Me._mb) ' raise our custom even that the form has subscribed to
Exit Sub ' Suppress default behavior
End Select
MyBase.WndProc(m)
End Sub
End Class
End Class
Public Class MyButton
Inherits Windows.Forms.Button
Protected Overridable Sub MyButton_Click(sender As Object, e As System.EventArgs) Handles Me.Click
MsgBox("Base Click")
End Sub
End Class
You are getting 2 messages because you have set 2 different event handlers for the Click event:
The MyButton_Click method defined in your MyButton class.
The Button_Click method set in your AddHandler call on the form.
As noted in a comment above, you need to override the Button.OnClick method in your MyButton class instead of creating a new method:
Imports System.Windows.Forms
Imports System.Drawing
Public Class MyButton
Inherits Windows.Forms.Button
Sub New()
End Sub
' Override the OnClick event defined in "Button" class.
Protected Overrides Sub OnClick(e As System.EventArgs)
' Call the Click event from "Button" class.
MyBase.OnClick(e)
' Some custom events.
MsgBox("MyButton Click")
End Sub
End Class
It might be a good exercise to set breakpoints in the Button_Click and MyButton.OnClick methods so you can see exactly how the stack is created.
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...
I have a two windows forms classes, a base class and a derived class. The base class has an event handler which handles ValueChanged on some component. I have also written a different event handler for the same event on the derived class.
When I create an instance of the derived class and fire the event, I find that both event handlers run (the base class one and then the derived class one). But I want only the handler in the derived class to run.
Is this possible and if so how do I do it?
(This is .NET 3.5)
Thanks!
Edit: Here is what the code looks like (can't post the actual code):
Public Class BaseForm
Inherits System.Windows.Forms.UserControl
(Windows Form Designer Generated Code)
Private WithEvents myControl As New SomeOtherControl
Protected value As String
Private Sub myControl_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles myControl.ValueChanged
value = SomeLogic()
End Sub
End Class
Public Class DerivedForm
Inherits BaseForm
Private WithEvents myControl As New SomeOtherControl
Private Sub myControl_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles myControl.ValueChanged
value = myControl.Value
End Sub
End Class
You can attach multiple handlers to one event so what you are seeing is by design (you have two handlers attached to the same event so they both fire).
That being said there are ways to accomplish what you are trying to do. One way is to move the code out of your base class handler into an overridable method, and then in the derived class override the method. So your base class handler only has 1 line of code,calling the new method you made. If you inherit from the class it will call your overridden method instead.
Public Class BaseForm
Private Sub myControl_ValueChanged() Handles myControl.ValueChanged
DoSomeLogic()
End Sub
Protected Overridable Sub DoSomeLogic()
'original logic here
End Sub
End Class
Public Class ChildForm
Inherits BaseForm
Protected Overrides Sub DoSomeLogic()
'other logic here
End Sub
End Class
I don't believe you can control that.
If it were me, I think I'd intercept the event in the base class, as you are doing, then define ANOTHER event from the base class and raise that event FROM the event handler in the base class.
on return, if the event was handled (presumably by your derived class), then just exit the base event handler, otherwise, proceed with the base event handling.
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