[dba-VB] inheriting events

Shamil Salakhetdinov shamil at users.mns.ru
Thu Jan 3 08:23:35 CST 2008


Hello John,

Here is another version of code, which is more suitable for the subject of
this thread - events can't be inherited in .NET AFAIK therefore you have to
simulate such inheritance by using base class's wrapper protected methods:

Option Explicit On

Public Interface IProxyProgress
    Event EventOne(ByVal msg As String)
    Event EventTwo(ByVal msg As String, ByVal count As Integer)
End Interface

Public Interface IFileProcessor
    Sub Execute(ByVal sleepInterval As Object)
End Interface

Public Class ProxyProgress
    Implements IProxyProgress
    Private Event EventOne(ByVal msg As String) _
                   Implements IProxyProgress.EventOne

    Private Event EventTwo(ByVal msg As String, ByVal count As Integer) _
                   Implements IProxyProgress.EventTwo

    Protected Sub RaiseEventOne(ByVal msg As String, ByVal eventSource As
Type)
        RaiseEvent EventOne(eventSource.ToString() + ": " + msg)
    End Sub

    Protected Sub RaiseEventTwo(ByVal msg As String, ByVal count As Integer,
ByVal eventSource As Type)
        RaiseEvent EventTwo(eventSource.ToString() + ": " + msg, count)
    End Sub
End Class

Public Class FileImporter
    Inherits ProxyProgress
    Implements IFileProcessor

    Private Sub Execute(ByVal sleepInterval As Object) _
                Implements IFileProcessor.Execute
        Dim interval As Integer = CType(sleepInterval, Integer)
        For i As Integer = 1 To 5
            RaiseEventOne("Event one", Me.GetType())
            System.Threading.Thread.Sleep(interval)
            RaiseEventTwo("Event two", i, Me.GetType())
            System.Threading.Thread.Sleep(interval)
        Next i
    End Sub

End Class

Public Class FileExporter
    Inherits ProxyProgress
    Implements IFileProcessor

    Private Sub Execute(ByVal sleepInterval As Object) Implements
IFileProcessor.Execute
        Dim interval As Integer = CType(sleepInterval, Integer)
        For i As Integer = 1 To 5
            RaiseEventOne("Event one", Me.GetType())
            System.Threading.Thread.Sleep(500)
            RaiseEventTwo("Event two", i, Me.GetType())
            System.Threading.Thread.Sleep(500)
        Next i
    End Sub
End Class

Module TestModule
    Private Sub EventOneHandler(ByVal msg As String)
        Console.WriteLine("EventOneHandler: " + msg)
    End Sub

    Private Sub EventTwoHandler(ByVal msg As String, ByVal count As Integer)
        Console.WriteLine(String.Format("EventTwoHandler: {0}, count = {1}",
msg, count))
    End Sub

    Sub Main()  ' Sync
        Dim list As List(Of IFileProcessor) = _
             New List(Of IFileProcessor)

        Dim fileProcessor As IFileProcessor = Nothing
        Dim proxyProgress As IProxyProgress = Nothing

        ' one
        fileProcessor = New FileImporter()
        proxyProgress = DirectCast(fileProcessor, IProxyProgress)
        AddHandler (proxyProgress.EventOne), AddressOf EventOneHandler
        AddHandler (proxyProgress.EventTwo), AddressOf EventTwoHandler
        list.Add(fileProcessor)
        ' two
        fileProcessor = New FileExporter()
        proxyProgress = DirectCast(fileProcessor, IProxyProgress)
        AddHandler (proxyProgress.EventOne), AddressOf EventOneHandler
        AddHandler (proxyProgress.EventTwo), AddressOf EventTwoHandler
        list.Add(fileProcessor)

        For Each fileProcessor In list
            fileProcessor.Execute(300)
        Next fileProcessor

        ' async test
        MainAsync()

    End Sub

    Sub MainAsync()
        Dim workers(2) As System.Threading.Thread

        Dim fileProcessor As IFileProcessor = Nothing
        Dim proxyProgress As IProxyProgress = Nothing

        ' one
        fileProcessor = New FileImporter()
        proxyProgress = DirectCast(fileProcessor, IProxyProgress)
        AddHandler (proxyProgress.EventOne), AddressOf EventOneHandler
        AddHandler (proxyProgress.EventTwo), AddressOf EventTwoHandler
        workers(0) = New Threading.Thread(AddressOf fileProcessor.Execute)
        ' two
        fileProcessor = New FileExporter()
        proxyProgress = DirectCast(fileProcessor, IProxyProgress)
        AddHandler (proxyProgress.EventOne), AddressOf EventOneHandler
        AddHandler (proxyProgress.EventTwo), AddressOf EventTwoHandler
        workers(1) = New Threading.Thread(AddressOf fileProcessor.Execute)

        workers(0).Start(200)
        workers(1).Start(1000)

    End Sub
End Module

--
Shamil
 
-----Original Message-----
From: dba-vb-bounces at databaseadvisors.com
[mailto:dba-vb-bounces at databaseadvisors.com] On Behalf Of Shamil
Salakhetdinov
Sent: Thursday, January 03, 2008 2:43 PM
To: dba-vb at databaseadvisors.com
Subject: Re: [dba-VB] inheriting events

Hi John,

Have a look below is the code you can use and generalize even more still
keeping it very simple. 

In fact there are two samples in this code: synchronous and asynchronous -
both work well in console mode as you can find. But the second async one has
to be changed to be used with WinForms because WinForms have their own UI
thread, and to call that thread properly from worker threads thread context
switching has to be implemented....


HTH,
Shamil

P.S. Code:

Option Explicit On

Public Interface IProxyProgress
    Event EventOne(ByVal msg As String)
    Event EventTwo(ByVal msg As String, ByVal count As Integer)
End Interface

Public Interface IFileProcessor
    Sub Execute(ByVal sleepInterval As Object)
End Interface

Public Class FileImporter
    Implements IProxyProgress
    Implements IFileProcessor

    Private Event EventOne(ByVal msg As String) _
                   Implements IProxyProgress.EventOne

    Private Event EventTwo(ByVal msg As String, ByVal count As Integer) _
                   Implements IProxyProgress.EventTwo

    Private Sub Execute(ByVal sleepInterval As Object) _
                Implements IFileProcessor.Execute
        For i As Integer = 1 To 5
            RaiseEvent EventOne("Event one from FileImporter")
            System.Threading.Thread.Sleep(500)
            RaiseEvent EventTwo("Event two from FileImporter", i)
            System.Threading.Thread.Sleep(500)
        Next i
    End Sub

End Class

Public Class FileExporter
    Implements IProxyProgress
    Implements IFileProcessor

    Private Event EventOne(ByVal msg As String) _
             Implements IProxyProgress.EventOne

    Private Event EventTwo(ByVal msg As String, ByVal count As Integer) _
            Implements IProxyProgress.EventTwo

    Private Sub Execute(ByVal sleepInterval As Object) Implements
IFileProcessor.Execute
        Dim interval As Integer = CType(sleepInterval, Integer)
        For i As Integer = 1 To 5
            RaiseEvent EventOne("Event one from FileExporter")
            System.Threading.Thread.Sleep(interval)
            RaiseEvent EventTwo("Event two from FileExporter", i)
            System.Threading.Thread.Sleep(interval)
        Next i
    End Sub
End Class

Module TestModule
    Private Sub EventOneHandler(ByVal msg As String)
        Console.WriteLine("EventOneHandler: " + msg)
    End Sub

    Private Sub EventTwoHandler(ByVal msg As String, ByVal count As Integer)
        Console.WriteLine(String.Format("EventTwoHandler: {0}, count = {1}",
msg, count))
    End Sub

    Sub Main()  ' Sync
        Dim list As List(Of IFileProcessor) = _
             New List(Of IFileProcessor)

        Dim fileProcessor As IFileProcessor = Nothing
        Dim proxyProgress As IProxyProgress = Nothing

        ' one
        fileProcessor = New FileImporter()
        proxyProgress = DirectCast(fileProcessor, IProxyProgress)
        AddHandler (proxyProgress.EventOne), AddressOf EventOneHandler
        AddHandler (proxyProgress.EventTwo), AddressOf EventTwoHandler
        list.Add(fileProcessor)
        ' two
        fileProcessor = New FileExporter()
        proxyProgress = DirectCast(fileProcessor, IProxyProgress)
        AddHandler (proxyProgress.EventOne), AddressOf EventOneHandler
        AddHandler (proxyProgress.EventTwo), AddressOf EventTwoHandler
        list.Add(fileProcessor)

        For Each fileProcessor In list
            fileProcessor.Execute(300)
        Next fileProcessor

        ' async test
        MainAsync()

    End Sub

    Sub MainAsync()
        Dim workers(2) As System.Threading.Thread

        Dim fileProcessor As IFileProcessor = Nothing
        Dim proxyProgress As IProxyProgress = Nothing

        ' one
        fileProcessor = New FileImporter()
        proxyProgress = DirectCast(fileProcessor, IProxyProgress)
        AddHandler (proxyProgress.EventOne), AddressOf EventOneHandler
        AddHandler (proxyProgress.EventTwo), AddressOf EventTwoHandler
        workers(0) = New Threading.Thread(AddressOf fileProcessor.Execute)
        ' two
        fileProcessor = New FileExporter()
        proxyProgress = DirectCast(fileProcessor, IProxyProgress)
        AddHandler (proxyProgress.EventOne), AddressOf EventOneHandler
        AddHandler (proxyProgress.EventTwo), AddressOf EventTwoHandler
        workers(1) = New Threading.Thread(AddressOf fileProcessor.Execute)

        workers(0).Start(200)
        workers(1).Start(1000)

    End Sub
End Module

--
Shamil
 
-----Original Message-----
From: dba-vb-bounces at databaseadvisors.com
[mailto:dba-vb-bounces at databaseadvisors.com] On Behalf Of jwcolby
Sent: Wednesday, January 02, 2008 9:40 PM
To: dba-vb at databaseadvisors.com
Subject: Re: [dba-VB] inheriting events

Sorry guys, I figured it out.

Basically I have a base class (clsProxyProgress) whose sole reason for its
existence is to raise events for derived classes.

I have one (at the moment) derived class (clsCSVDataExportSpec) which can
then use its parent clsProxyProgress to raise events for it.
clsCSVDataExportSpec supervises EXPORTING data.

I have a frmProxyProgress whose sole purpose is to sink the events raised
via clsProxyProgress and display progress data for classes derived from
clsProxyProgress - clsCSVDataExportSpec in this case.  IOW it is
clsCSVDataExportSpec that wants to display status information, and it does
so via clsProxyProgress (its parent).

I have a supervisor class that creates instances of clsCSVDataExportSpec.  I
may have 1 or 5 different CSV Exports happening, and the supervisor class
loads and starts them running.  These instances of clsCSVDataExportSpec are
run periodically which is why there may be 1 or N, it just depends on
whether it is time to run a specific instance.

Each instance of clsCSVDataExportSpec gets data that tells it whether or not
to open a display form frmProxyProgress to display its progress in.

clsCSVDataExportSpec does not NEED a progress form in order to function, it
simply displays its progress data in a frmProxyProgress instance if it is
told to do so.  In fact it simply INSTANTIATES a frmProxyProgress if it is
told to do so.  It always raises the events that would be displayed in
frmProxyProgress even if it does not have a display form open to use.

clsProxyProgress and frmProxyProgress can also be used for
clsCSVDataImportSpec.  clsCSVDataImportSpec is a class which supervises
IMPORTING data.  There may be 1 or N copies of clsCSVDataImportSpec.
Likewise clsCSVDataImportSpec can be told to display it's progress in an
instance of frmProxyProgress.  There are also two flat file process classes
that can use clsProxyProgress and frmProxyProgress. Each of them can have 1
or N instances running.  As you can see there can be nothing running or
there can be a dozen different CSV or FlatFile imports or exports running,
all at the "same" time.  Each can display a progress or not.

So the point here is that by creating clsProxyProgress and frmProxyProgress,
I have a form that sinks events from clsProxyProgress, and four different
Flat/CSV Import/Export classes that inherit clsProxyProgress.  Because they
all inherit the same class, they can all raise the same events up in the
base class, but more importantly I now have just one proxy class and one
proxy form that handles all of the raising / sinking of these events and
displaying the status in form instances.

The key to get it all working is that I needed to know that I could pass a
derived class into a declaration of a base class in the New() sub.

In the proxy FORM:

'
'Dimension a base class variable WithEvents
'
private WithEvents mclsProxyProgress  as clsProxyProgress
'
'In New() receive a base class instance
'
sub new( lclsProxyProgress as clsProxyProgress)
	'
	'Set the module level variable = to the instance pointer passed in
to new()
	'
	mclsProxyProgress = lclsProxyProgress
end sub

'
'Sink events for the base class here and perform some action (display a
status for example)
'
sub mslcProxyProgress_SomeEventSink(strStatus as string)
	txtStatus.text = strStatus
end sub

In the base class:
'
'Dimension a form variable to use to display the status
'
private mfrmDisplay as form
'
'Open a form and pass in a pointer to me
'
sub OpenDisplayForm()
	set mfrmDisplay = new frmProxyProgress(me)
	frmProxyProgress.Show 
end sub

NOTICE that I passed in a pointer to the DERIVED class but the form's New()
expects a variable of the Base class.  That works, and that is what I was
stumbling over.  I did not realize that VB.Net would dynamically cast a
derived class into a base class in this fashion.

With all this in place, I can have 1 to N instances of many different
derived classes (siblings) of the base class clsProxyProgress.  All the
derived classes (siblings) can use the same form (but not the same INSTANCE
of that form) to display its progress.  Each instance of a derived class can
have its own instance of a status form and display its status in that form
instance.

Sometimes when I don't understand what I am doing, I can't explain what I
don't understand well enough to get help in understanding it.

Or MAYBE (as William is wont to say) I am just obtuse.

I think I now need to go back into the base class and declare it MustInherit
and declare all of the methods ... uh... friend?  Or protected?  Another
thing that I do not understand at all really.

John W. Colby
Colby Consulting
www.ColbyConsulting.com 
-----Original Message-----
From: dba-vb-bounces at databaseadvisors.com
[mailto:dba-vb-bounces at databaseadvisors.com] On Behalf Of Charlotte Foust
Sent: Wednesday, January 02, 2008 12:27 PM
To: dba-vb at databaseadvisors.com
Subject: Re: [dba-VB] inheriting events

I'm not sure I understand what you're trying to do, John.  Your
clsdDSVDataExportSpec inherits the methods and properties of the class
clsProxyProgress, it doesn't inherit things happening to
clsProxyProgress.   We have a TransferHelper class which doesn't inherit
anything.  We have classes for Import and Export that are declared as Public
MustInherit, with all their methods and properties declared as protected.
Then we have specific transfer method classes that inherit the MustInherit
classes and that handle the specific operations required for a particular
type of import or export.  The TransferHelper class has shared methods and
properties, so we can call them by code like TransferHelper.ImportCSV(args).


I don't see what you're trying to do by raising a "status" event.  Are you
logging the work?  We use a separte EventLogItem class to wrap the creation
of event log items.

Charlotte Foust 

_______________________________________________
dba-VB mailing list
dba-VB at databaseadvisors.com
http://databaseadvisors.com/mailman/listinfo/dba-vb
http://www.databaseadvisors.com

_______________________________________________
dba-VB mailing list
dba-VB at databaseadvisors.com
http://databaseadvisors.com/mailman/listinfo/dba-vb
http://www.databaseadvisors.com




More information about the dba-VB mailing list