Results 1 to 7 of 7

Thread: pass delegate [resolved]

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    May 2005
    Posts
    530

    pass delegate [resolved]

    Hello all,
    How do you pass a delegate to a class such that it can call back to a function on the parent form? (VB.NET 2003)
    Thanks.
    Last edited by rickford66; Jan 26th, 2007 at 02:26 PM.

  2. #2

    Thread Starter
    Fanatic Member
    Join Date
    May 2005
    Posts
    530

    Re: pass delegate

    I figured it out.

  3. #3
    Addicted Member
    Join Date
    Apr 2003
    Location
    Australia
    Posts
    252

    Pass a Function or Sub as a Parameter?

    Hi All,

    I am asking too many questions too often and it looks like I am not doing my research but I really do. It's just that I code and learn during weekends and all questions arise in a short interval.

    For a while I was looking for a way to Pass a Function or Sub as a Parameter, if this is what you were trying to find rickford?

    Here is my problem. I have many functions (Background Worker tasks) that I like to do in a Try/Catch block for FINAL versions and without Try/Catch block for BETA versions.

    VB Code:
    1. Private Sub bwApp_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bwApp.DoWork
    2.  
    3.         Dim t As New cBwJob(cBwJob.JobType.NEW_TASK)
    4.         t = CType(e.Argument, cBwJob)
    5.  
    6.         Select Case t.Job
    7.  
    8.             Case cBwJob.JobType.ADD_NEW_TRACKS
    9.                 sBwAppAddNewFilesToLibrary(t.TaskData)
    10.  
    11.             Case cBwJob.JobType.CAPITALIZE_FIRST_LETTER
    12.                 sBwAppCaptitalizeWord()
    13.  
    14.             Case cBwJob.JobType.FIND_NEW_TRACKS_FROM_HDD
    15.                 sBwAppFindNewTracksFromHDD()
    16.  
    17.             Case cBwJob.JobType.INITIALIZE_ITUNES
    18.                 sBwAppLoadItunes()
    19.  
    20.             Case cBwJob.JobType.LOAD_ALBUMS
    21.                 sBwAppFillTrackCount()
    22.  
    23.             Case cBwJob.JobType.RATINGS_BACKUP
    24.                 sBwAppRatingsBackup()
    25.  
    26.             Case cBwJob.JobType.RATINGS_RESTORE
    27.                 sBwAppRatingsRestore()
    28.  
    29.             Case cBwJob.JobType.RECOVER_TAGS
    30.                 sBwAppRecoverTags()
    31.  
    32.             Case cBwJob.JobType.REPLACE_WORD
    33.                 sBwAppReplaceTextInTags()
    34.  
    35.             Case cBwJob.JobType.VALIDATE_LIBRARY
    36.  
    37.                 If mAppInfo.ApplicationState = AppInfo.SoftwareCycle.FINAL Then
    38.                     sBwAppValidateLibrary()
    39.                 Else
    40.                     Try
    41.                         sBwAppValidateLibrary()
    42.                     Catch ex As Exception
    43.                         mErrOccured = True
    44.                         Dim lErrLog As New System.IO.StreamWriter(mFilePathErrorLog)
    45.                         lErrLog.WriteLine(String.Format("{0}", ex.Message))
    46.                         lErrLog.WriteLine(String.Format("{0}", ex.StackTrace))
    47.                         lErrLog.Close()
    48.                     End Try
    49.                 End If
    50.  
    51.         End Select
    52.  
    53.     End Sub

    If you look at the code above, I have done this for ONE BackgroundWorder tasks and I would like to extend this to all the other tasks. I could do it, but ideally I was hoping for something like this to do:


    VB Code:
    1. Private Sub sPerformTask(Function myFunction)
    2.  
    3.      If mAppInfo.ApplicationState = AppInfo.SoftwareCycle.FINAL Then
    4.  
    5.      Try
    6.              Call myFunction()
    7.          Catch ex As Exception
    8.              mErrOccured = True
    9.              Dim lErrLog As New System.IO.StreamWriter(mFilePathErrorLog)
    10.              lErrLog.WriteLine(String.Format("{0}", ex.Message))
    11.              lErrLog.WriteLine(String.Format("{0}", ex.StackTrace))
    12.              lErrLog.Close()
    13.          End Try
    14.  
    15.      Else
    16.        
    17.      Call myFunction()
    18.        
    19.      End If
    20.  
    21. End Sub

    So I can call this like

    VB Code:
    1. sPerformTask(sBwAppReplaceTextInTags())
    VB Code:
    1. sPerformTask(sBwAppReplaceTextInTags())
    VB Code:
    1. sPerformTask(sBwAppReplaceTextInTags())

    Etc...

    I hope I am making myself clear.

    Any help would be much appreciated.

    Thanks,
    McoreD

  4. #4

    Thread Starter
    Fanatic Member
    Join Date
    May 2005
    Posts
    530

    Re: pass delegate [resolved]

    I'm not sure what you are trying to do or even if what I was working on would relate. Let me explain a bit more about what I was asking. I have a main form that holds an instance of a class. Inside this class, I was pulling data from a sound card. The class was set up such that when the sound card filled a buffer, it called a callback routine in my class. Now, with the class knowing about this new data, I wondered how could I get the form to know about it as well. Having the form continuously poll the class seemed like a hack job to me, and I didn't know how to, or even if it was possible to raise an event in the class that would be consumed by the form. I decided to use a delegate. By using a delegate, I created a sub in the form to resond to the class, then I assigned the address of that sub to the delegate in the class. Then, when the class needed to tell the form of the new data, it just called the function in the form using the delegate. The number (BufferNumber) that the class passes to the form is for diagnostic purposes, as I am still having trouble with the sound card interface.... but this callback works great. Here is the code...

    In the class, I created a delegate
    VB Code:
    1. Public delBufferFull As BufferFull
    and a property in the class by which I could set up the delegate
    VB Code:
    1. Public WriteOnly Property SetupBufferFullDelegate() As BufferFull
    2.         Set(ByVal Value As BufferFull)
    3.             delBufferFull = Value  'load with address of sub in parent form
    4.         End Set
    5.     End Property
    In the form, I made the sub
    VB Code:
    1. Private Sub HandleBufferFull(ByVal BufferNumber As Int32)
    2.         byDataArray = objInputToBuffer.ReadBuffer
    3.         ProcessSoundData()  'data to progress bars
    4.     End Sub
    and passed the address of the sub to the delegate in the class (objInputToBuffer is the name, in the form, of the instance of clsInputToBuffer2).
    VB Code:
    1. objInputToBuffer.SetupBufferFullDelegate = AddressOf HandleBufferFull  'inform class where to call when data is ready
    Then, from within the class, I called the sub in the form
    VB Code:
    1. delBufferFull.Invoke(k)  'tell the parent form so it will read data from array
    k is the diagnostic number that is passed into HandleBufferFull as BufferNumber. That's it. If this isn't what you're looking for, I'd suggest you post in a new thread so you get a lot more eyes looking at it.

  5. #5
    Addicted Member
    Join Date
    Apr 2003
    Location
    Australia
    Posts
    252

    Re: pass delegate [resolved]

    I think you are right there about posting a new thread.
    Thanks for the reply rick, although it wasn't what I was really after, just like you assumed. Invoke method is similar to my idealized sPerformTask function that takes a function as a parameter.

  6. #6
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: pass delegate [resolved]

    McodeD:

    First of all, all those If statements are a bad idea. You shouldn't be compiling both sets of code if you don't need to. You should be declaring a conditional compilation constant in the project properties and then only compiling the appropriate code into the current version, e.g.
    VB Code:
    1. #If BETA Then
    2.     'Write beta code here.
    3. #Else
    4.     'Write final code here.
    5. #End If
    In your case you could even do this:
    VB Code:
    1. #If BETA Then
    2.         Try
    3. #End If
    4.  
    5.         'Write actual code here.
    6.  
    7. #If BETA Then
    8.         Catch ex As Exception
    9.  
    10.         End Try
    11. #End If
    That way the Try and the Catch...End Try will only get compiled into beta versions while the actual code you want executed will be compiled in all code.

    Now, you are on the right track with asking about delegates. A delegate is an object that contains a reference to a method. If you feel like you want to pass a method around then what you actually need to do is create a delegate that contains a reference to that that method and pass it around. When you want to execute the method you simply call the delegate's Invoke method. Logically, if you want to fo this:
    VB Code:
    1. Private Sub Method1()
    2.     MessageBox.Show("Hello World")
    3. End Sub
    4.  
    5. Private Sub Method2()
    6.     Method3(Method1)
    7. End Sub
    8.  
    9. Private Sub Method3(myMethod As Sub)
    10.     Call myMethod
    11. End Sub
    what you actually need to do is this:
    VB Code:
    1. Private Sub Method1()
    2.     MessageBox.Show("Hello World")
    3. End Sub
    4.  
    5. Private Sub Method2()
    6.     Method3(New MethodInvoker(AddressOf Method1))
    7. End Sub
    8.  
    9. Private Sub Method3(ByVal myMethod As MethodInvoker)
    10.     myMethod.Invoke()
    11. End Sub
    MethodInvoker is an existing delegate type that you can use for methods with no arguments and no return value. If your method has either of those then you need to declare your own delegate, e.g.
    VB Code:
    1. Private Delegate Function QuestionAsker(ByVal question As String) As DialogResult
    2.  
    3. Private Function AskQuestion(ByVal question As String) As DialogResult
    4.     Return MessageBox.Show(question, "Yes or No", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
    5. End Function
    6.  
    7. Private Sub Method2()
    8.     Method3(New QuestionAsker(AddressOf AskQuestion))
    9. End Sub
    10.  
    11. Private Sub Method3(ByVal myMethod As QuestionAsker)
    12.     Dim result As DialogResult = DirectCast(myMethod.Invoke("Are you male?"), DialogResult)
    13.  
    14.     Select Case result
    15.         Case Windows.Forms.DialogResult.Yes
    16.             MessageBox.Show("You are male.")
    17.         Case Windows.Forms.DialogResult.No
    18.             MessageBox.Show("You are female.")
    19.     End Select
    20. End Sub
    There are several things to note here:

    1. The delegate has the same signature as the method it will reference.
    2. The parameters that you pass when calling Invoke are the same parameters that get passed to the reference method when it's executed.
    3. The value returned by the referenced method is the same value that gets returned by Invoke. Having said that, Invoke returns an Object reference so you must cast it as the actual type returned by the referenced method.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  7. #7
    Addicted Member
    Join Date
    Apr 2003
    Location
    Australia
    Posts
    252

    Re: pass delegate [resolved]

    Sorry for my duplicate post: http://www.vbforums.com/showthread.php?t=449681

    Not my style and will not happen again.

    Thanks,
    McoreD

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width