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