Solved

VB.Net Delegate Question

Posted on 2009-05-19
9
292 Views
Last Modified: 2013-12-17
I have a vb.net class (I'll call Class1) that includes two sub routines.  The first sub is called Start, and it does the general work of the class.  As it does its thing, if a variable called DoDebug is set to true, it periodically calls the other sub routine called WriteDebug.  WriteDebug accepts a string as a parameter and appends the string to a file.  

This class normally runs as part of a windows service.  For testing purposes though, I created a windows forms project with one form (Form1) and added Class1 to it.  I created a button on Form1 that calls the start routine of Class1.  I then created a textbox on Form1.  What I would like to do is have the text box display the strings that are passed to the WriteDebug method of class1. I don't want Class1 to reference anything on the form though because Form1 won't exist when Class1 runs as part of my windows service.

I assume I would do this with delegates?  Can I create a delegate sub in Class1 and invoke it in the WriteDebug routine?  I have put some code below that does not work.  Somebody set me straight, please!  How should this be done?
Public Class Class1
 

'The delegate stuff in class 1:

Public Delegate Sub GetMessage(ByVal strData As String)

Private _GetMessage As GetMessage

Public Sub GetMessages(ByVal del As GetMessage)

    _GetMessage = del

End Sub
 

'The main routine in Class1

Public Sub Start()

    'code here to do stuff

End Sub
 

'The routine to invoke the delegate and pass the string to Form1

Private Sub WriteDebug(strData as String)

    'code here to write to file

     _GetMessage.Invoke(strData)

End Sub
 

End Class
 
 

Public Class Form1

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    Dim c as new Class1

    Dim delegateGetMessages As New Class1.GetMessage(AddressOf ShowMessage)

    c.GetMessages(delegateGetMessages)

    c.Start

End Sub
 

Private Sub ShowMessage(ByVal strData As String)

    TextBox1.Text += strData

End Sub

Open in new window

0
Comment
Question by:grantdaddy
  • 4
  • 3
  • 2
9 Comments
 
LVL 85

Accepted Solution

by:
Mike Tomlinson earned 500 total points
ID: 24427474
You need a custom EVENT in Class1.  Use the AddHandler() method to wire up the event in your form (and in your service).

Simple example with the Form:
(note that Class1 has no idea who has subscribed to its event...it simply raises it and all subscribers are notified)
Public Class Form1
 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim c1 As New Class1

        AddHandler c1.WriteDebugReceived, AddressOf c1_WriteDebugReceived

        c1.Start()

    End Sub
 

    Private Sub c1_WriteDebugReceived(ByVal strData As String)

        MessageBox.Show(strData, "WriteDebugReceived()", MessageBoxButtons.OK, MessageBoxIcon.Information)

    End Sub
 

End Class
 

Public Class Class1
 

    Public Event WriteDebugReceived(ByVal strData As String)
 

    Public Sub Start()

        System.Threading.Thread.Sleep(5000) ' simulated 5 second long "work"
 

        Dim someCondition As Boolean = True

        If someCondition Then

            WriteDebug("Hello World!")

        End If

    End Sub
 

    Private Sub WriteDebug(ByVal strData As String)

        'code here to write to file

        RaiseEvent WriteDebugReceived(strData)

    End Sub
 

End Class

Open in new window

0
 
LVL 12

Expert Comment

by:omegaomega
ID: 24427477
Hello, grantdaddy,

As far as I can see, your delegate is OK.  

Perhaps the problem that you are seeing is because the form cannot complete loading until c.Start completes.  In the attached snippet, I have moved your call to c.Start to a button click event (and given "c" module scope so that it doesn't disappear after the form load event completes).  I've added some trivial test code to the Start method at the point of "'code here to do stuff" and find that with those changes everything works fine for me.

If that's not the problem though, post back with more specifics and we'll see what we can figure out.

Cheers,
Randy

Public Class Form1
 

    Private c As New Class1
 

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        ' ''Dim c As New Class1

        Dim delegateGetMessages As New Class1.GetMessage(AddressOf ShowMessage)

        c.GetMessages(delegateGetMessages)

        ' ''c.Start()

    End Sub
 

    Private Sub ShowMessage(ByVal strData As String)

        TextBox1.Text += strData

    End Sub
 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        c.Start()

    End Sub

End Class
 
 

Public Class Class1
 

    'The delegate stuff in class 1:

    Public Delegate Sub GetMessage(ByVal strData As String)

    Private _GetMessage As GetMessage

    Public Sub GetMessages(ByVal del As GetMessage)

        _GetMessage = del

    End Sub
 

    'The main routine in Class1

    Public Sub Start()

        'code here to do stuff

        For intCounter As Integer = 1 To 10

            Me.WriteDebug(Now.ToString("HH:mm:ss.fff") & vbCrLf)

            Application.DoEvents()

            System.Threading.Thread.Sleep(1000)

        Next intCounter
 

    End Sub
 

    'The routine to invoke the delegate and pass the string to Form1

    Private Sub WriteDebug(ByVal strData As String)

        'code here to write to file

        _GetMessage.Invoke(strData)

    End Sub
 

End Class

Open in new window

0
 
LVL 12

Expert Comment

by:omegaomega
ID: 24427521
Hello, grantdaddy,

Even if you can get the "delegate" assignment approach you are trying to work, you might want to consider switching to the Event/Handler approach that Idle_Mind is recommending.  I think that the two are basically equivalent, but the Event/Handler approach Idle-Mind recommends is going to be a bit easier to understand for others who come after you to maintain the code.

Cheers,
Randy
0
 

Author Closing Comment

by:grantdaddy
ID: 31583280
Thanks!  That works great!  I was making it too difficult.
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24431911
Glad you found it useful!  I would have given points to omegaomega too, though, for showing how to make it work with the original "specs"...  =\
0
 

Author Comment

by:grantdaddy
ID: 24432819
I have one more problem with this solution.  I created an event in Class1 that accepts a string parameter and had Form1 handle the event, just like Idle_Mind suggested above.  However, I left out an important piece of information.  The code in Class1 that calls the WriteDebug method actually exectues on a timer elapsed event, which means it is in a separate thread.  So I am getting an error message that says "Cross-thread operation not valid" when Form1 tries to update the text box control.  Do you know how to handle this?
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24432965
Yes...you use a Delegate/Invoke() approah.   (There are other solutions as well)

Here is a modified example demonstrating the concept:
Public Class Form1

 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim c1 As New Class1

        AddHandler c1.WriteDebugReceived, AddressOf c1_WriteDebugReceived

        c1.Start()

    End Sub

 

    Public Delegate 

    Private Sub c1_WriteDebugReceived(ByVal strData As String)

        MessageBox.Show(strData, "WriteDebugReceived()", MessageBoxButtons.OK, MessageBoxIcon.Information)

    End Sub

 

End Class

Open in new window

0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24432979
The last code snippet didn't post completely...  =\

Here she is:
Public Class Form1
 

    Private Delegate Sub WriteDebugDelegate(ByVal strData As String)
 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim c1 As New Class1

        AddHandler c1.WriteDebugReceived, AddressOf c1_WriteDebugReceived

        c1.Start()

    End Sub
 

    Private Sub c1_WriteDebugReceived(ByVal strData As String)

        If Me.InvokeRequired Then

            Me.Invoke(New WriteDebugDelegate(AddressOf c1_WriteDebugReceived), New Object() {strData})

        Else

            TextBox1.Text = strData

        End If

    End Sub
 

End Class
 

Public Class Class1
 

    Public Event WriteDebugReceived(ByVal strData As String)
 

    Public Sub Start()

        Dim T As New System.Threading.Thread(AddressOf Worker)

        T.Start()

    End Sub
 

    Private Sub Worker()

        System.Threading.Thread.Sleep(5000) ' simulated 5 second long "work"

        Dim someCondition As Boolean = True

        If someCondition Then

            WriteDebug("Hello World!")

        End If

    End Sub
 

    Private Sub WriteDebug(ByVal strData As String)

        'code here to write to file

        RaiseEvent WriteDebugReceived(strData)

    End Sub
 

End Class

Open in new window

0
 

Author Comment

by:grantdaddy
ID: 24433453
Thank you so much for following up with me.  This works perfectly.  And I think I finally understand how a delegate works.
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

The ECB site provides FX rates for major currencies since its inception in 1999 in the form of an XML feed. The files have the following format (reducted for brevity) (CODE) There are three files available HERE (http://www.ecb.europa.eu/stats/exch…
A long time ago (May 2011), I have written an article showing you how to create a DLL using Visual Studio 2005 to be hosted in SQL Server 2005. That was valid at that time and it is still valid if you are still using these versions. You can still re…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now