|
-
Jan 1st, 2008, 01:29 AM
#1
Thread Starter
New Member
[RESOLVED] Raise / sink events defined in parent class
I designed a base class which has events:
Code:
Public Class clsProxyProgress
Public Event evProcessName(ByVal strProcessName As String)
Public Event evDirectory(ByVal strDirectory As String)
Public Event evCurrentFile(ByVal strCurrentFile As String)
Public Event evFilesCompleted(ByVal intFilesCompleted As Integer)
Public Event evFileCnt(ByVal intFileCnt As Integer)
Public Event evRowsCopied(ByVal intRowsCopied As Long)
Public Event evStatus(ByVal strStatus As String)
I then inherit that class in a child class.
Code:
Public Class clsCSVDataExportSpec
Inherits clsProxyProgress
The child class clsCSVDataExportSpec cannot "see" the events in the parent, i.e. it cannot do:
Code:
RaiseEvent evStatus(mstrStatus)
even though its parent class has that event. If I try to do this in the child class I get a compile error.
In order to get around this I created functions in the parent class clsProxyProgress
Code:
Public Sub mStatus(ByVal strStatus As String, ByVal blnStatusReset As Boolean, ByVal blnStatusTimeStamp As Boolean)
If blnStatusReset Then mstrStatus = ""
If blnStatusTimeStamp Then
mstrStatus = mstrStatus & vbCrLf & Now()
End If
If Len(mstrStatus) > 0 Then
mstrStatus = mstrStatus & vbCrLf & strStatus
Else
mstrStatus = strStatus
End If
RaiseEvent evStatus(mstrStatus)
End Sub
NOTICE that in the last line of the sub I raise the evStatus. I then call this sub from the child clsCSVDataExportSpec so that the parent class clsProxyProgress raises the event for the child class. I do this simply because if I try to raise the event up in the parent class directly from the child class I get a compile error.
The whole point of this stuff is to allow a form to sink events and display data in text boxes on the form.
In a form class I dimension a variable for this child class:
Code:
Private WithEvents fclsCSVDataExport As clsCSVDataExportSpec
further down I "sink" the events for this class:
Code:
Private Sub fclsCSVDataExport_evStatus(ByVal strStatus As String) Handles fclsCSVDataExport.evStatus
txtStatus.Text = strStatus
Application.DoEvents()
End Sub
In the "Handles ..." the evStatus is a choice in the intellisense dropdown, IOW this form's module "sees" the event that the child class fclsCSVDataExport inherits from its parent class clsProxyProgress. However the sub fclsCSVDataExport_evStatus() never receives control when the Raisevent is executed.
I SUSPECT that the issue is that the "Handles ..." needs to be "Handles fclsProxyProgress", i.e. it needs to "handle" the parent of fclsCSVDataExport, not fclsCSVDataExport itself.
fclsCSVDataExport is the actual class that performs the data export for me.
clsProxyProgress only exists to allow several different such import / export classes inherit common events and code, and I do that so that I can
(eventually) have a generic form that dimensions a clsProxyProgress rather than having a specific import or export class such as clsCSVDataExport or clsCSVDataImport.
If anyone is following what I am doing and can point me to how to make this work it would be appreciated.
Thanks,
jwc
-
Jan 1st, 2008, 01:54 AM
#2
Frenzied Member
Re: Raise / sink events defined in parent class
http://msdn2.microsoft.com/en-us/lib...w3(VS.80).aspx
Code:
Imports System
Imports System.Collections.Generic
Namespace BaseClassEvents
' Special EventArgs class to hold info about Shapes.
Public Class ShapeEventArgs
Inherits EventArgs
Private m_newArea As Double
Public Sub New(ByVal d As Double)
m_newArea = d
End Sub
Public ReadOnly Property NewArea() As Double
Get
Return m_newArea
End Get
End Property
End Class
' Base class event publisher
Public MustInherit Class Shape
Protected m_area As Double
Public Property Area() As Double
Get
Return m_area
End Get
Set
m_area = value
End Set
End Property
' The event. Note that by using the generic EventHandler<T> event type
' we do not need to declare a separate delegate type.
Public Event ShapeChanged As EventHandler(Of ShapeEventArgs)
Public MustOverride Sub Draw()
'The event-invoking method that derived classes can override.
Protected Overridable Sub OnShapeChanged(ByVal e As ShapeEventArgs)
' Make a temporary copy of the event to avoid possibility of
' a race condition if the last subscriber unsubscribes
' immediately after the null check and before the event is raised.
Dim handler As EventHandler(Of ShapeEventArgs) = ShapeChanged
RaiseEvent handler(Me, e)
End Sub
End Class
Public Class Circle
Inherits Shape
Private radius As Double
Public Sub New(ByVal d As Double)
radius = d
area = 3.14 * radius
End Sub
Public Sub Update(ByVal d As Double)
radius = d
area = 3.14 * radius
OnShapeChanged(New ShapeEventArgs(area))
End Sub
Protected Overloads Overrides Sub OnShapeChanged(ByVal e As ShapeEventArgs)
' Do any circle-specific processing here.
' Call the base class event invocation method.
MyBase.OnShapeChanged(e)
End Sub
Public Overloads Overrides Sub Draw()
Console.WriteLine("Drawing a circle")
End Sub
End Class
Public Class Rectangle
Inherits Shape
Private length As Double
Private width As Double
Public Sub New(ByVal length As Double, ByVal width As Double)
Me.length = length
Me.width = width
area = length * width
End Sub
Public Sub Update(ByVal length As Double, ByVal width As Double)
Me.length = length
Me.width = width
area = length * width
OnShapeChanged(New ShapeEventArgs(area))
End Sub
Protected Overloads Overrides Sub OnShapeChanged(ByVal e As ShapeEventArgs)
' Do any rectangle-specific processing here.
' Call the base class event invocation method.
MyBase.OnShapeChanged(e)
End Sub
Public Overloads Overrides Sub Draw()
Console.WriteLine("Drawing a rectangle")
End Sub
End Class
' Represents the surface on which the shapes are drawn
' Subscribes to shape events so that it knows
' when to redraw a shape.
Public Class ShapeContainer
Private _list As List(Of Shape)
Public Sub New()
_list = New List(Of Shape)()
End Sub
Public Sub AddShape(ByVal s As Shape)
_list.Add(s)
AddHandler s.ShapeChanged, AddressOf HandleShapeChanged
' Subscribe to the base class event.
End Sub
' ...Other methods to draw, resize, etc.
Private Sub HandleShapeChanged(ByVal sender As Object, ByVal e As ShapeEventArgs)
Dim s As Shape = DirectCast(sender, Shape)
' Diagnostic message for demonstration purposes.
Console.WriteLine("Received event. Shape area is now {0}", e.NewArea)
' Redraw the shape here.
s.Draw()
End Sub
End Class
Class Test
Private Shared Sub Main(ByVal args As String())
'Create the event publishers and subscriber
Dim c1 As New Circle(54)
Dim r1 As New Rectangle(12, 9)
Dim sc As New ShapeContainer()
' Add the shapes to the container.
sc.AddShape(c1)
sc.AddShape(r1)
' Cause some events to be raised.
c1.Update(57)
r1.Update(7, 7)
' Keep the console window open.
Console.WriteLine()
Console.WriteLine("Press Enter to exit")
Console.ReadLine()
End Sub
End Class
End Namespace
Last edited by FourBlades; Jan 1st, 2008 at 02:02 AM.
-
Jan 1st, 2008, 09:44 AM
#3
Thread Starter
New Member
Re: Raise / sink events defined in parent class
Thanks for the reply. I printed it out and am studying it but am not having much luck understanding the pieces and how to relate them back to my problem. It kinda looks like a "similar problem".
What I am trying to accomplish is to have a generic form on which I display identical information from different classes. The work classes perform input from and output to files from a database. All that stuff is working. I just need to display status, things like the current file being processed, the % complete and so forth. The work classes do not NEED the status forms in order to function (thus raising events), the status is logged into files and also into tables in the databases, the status forms are just for my visually observing the process running, troubleshooting etc.
Obviously I could just build a form for each such working class but given that they all are completely identical except for the working class sending the information, I thought I would try to use events. I understand events, IF the working class is dimensioned Withevents directly in the form used to display the status.
My thought was that I would define a base class to define the events and a sub in the base class to raise each event, inherit that in each working class, then call the sub in the base to raise the event. All of THAT works. The problem appears to be in how to sink the events in the form.
I am trying to have a supervisor process instantiate each working class, dimension and open the status display form (if desired), then pass in a pointer to the working class into the status form. The form stores the pointer into a withevents variable "somehow", that variable has event sinks. Eventually there may be several working classes functioning at the same time (using threads). Each process may or may not have a status form opened and dedicated to it. That will be determined by a supervisor which starts and stops the working classes and status forms. If the working class "has a status form" then the form will be opened by the supervisor and the form will be passed in a working class to monitor the events for.
The "somehow" is my conceptual issue. The variable in the generic status form cannot be dimensioned of the type of the base class or the whole point of the excercise is lost, I now have a form specific to that working class. So the Withevent variable in the status form has to be of the base type inherited by the working class. Perhaps I can typecast the working class object passed in to the status form to be of the base class type, and store the type casted pointer. Since it is now of the base class and not the working class, then the event sinks work?
Unfortunately I am new to this stuff as you can no doubt tell, so my command of the syntax is lacking.
To recap, I have a base class which can rais events. It has a sub for each event to be raised. I have working classes which all inherit the base class. I have a generic status display form. I have a supervisor which instantiates a working class object, opens an instance of the status form and passes in a pointer to the working class object.
What does not work is that the events in the display form does not correctly sink the events, i.e. control never passes to the event sink.
Last edited by jwcolby; Jan 1st, 2008 at 10:05 AM.
-
Jan 1st, 2008, 12:58 PM
#4
Re: Raise / sink events defined in parent class
A couple things that may have already been covered, but it's early:
1) Since you raise all the events from the base class, wouldn't you be declaring the classes in the form as WithEvents BaseClass, rather than the derived class. Every derived class should be able to be used as a pointer to its base class, so if all of the working classes are derived from a common base, you should only need to declare base classes in the form and the declared variables should be able to accept any of the derived classes. Then the normal event handling should be fine.
2) If these classes work in separate threads, you're going to have some synchronization issues if you try to write to the UI thread from a child thread. If you've already thought that through, it won't be an issue, but raising events on the UI thread such that you can write to a control when the event fires isn't quite the same as in the single threaded model.
My usual boring signature: Nothing
 
-
Jan 2nd, 2008, 07:39 AM
#5
Thread Starter
New Member
Re: Raise / sink events defined in parent class
 Originally Posted by Shaggy Hiker
1) Since you raise all the events from the base class, wouldn't you be declaring the classes in the form as WithEvents BaseClass, rather than the derived class. Every derived class should be able to be used as a pointer to its base class, so if all of the working classes are derived from a common base, you should only need to declare base classes in the form and the declared variables should be able to accept any of the derived classes. Then the normal event handling should be fine.
2) If these classes work in separate threads, you're going to have some synchronization issues if you try to write to the UI thread from a child thread.
1) Yes, that is the idea.
2) What are the issues there? I have seen implications that you can't update controls from a worker thread but nothing specific or how to program around it. Each process class will have its own form to display in (if it has a form at all).
-
Jan 2nd, 2008, 09:08 AM
#6
Thread Starter
New Member
Re: Raise / sink events defined in parent class
Woohooo, Success!!! It turns out it was as simple as passing in the derived class to a variable of the type base class in the New() of the form, then setting that base class passed in into a base class variable dimensioned WithEvents in the header of the form. Voila, the status form started working, sinking the events from the derived class.
Thanks for your help guys, much appreciated.
-
Jan 2nd, 2008, 11:07 AM
#7
Re: [RESOLVED] Raise / sink events defined in parent class
Well, if it's working, I guess we can ignore my #2 point.
My usual boring signature: Nothing
 
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|