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.
Printable View
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.
I figured it out.
Hi All,
I am asking too many questions too often and it looks like I am not doing my research but I really do. :o 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:
Private Sub bwApp_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bwApp.DoWork Dim t As New cBwJob(cBwJob.JobType.NEW_TASK) t = CType(e.Argument, cBwJob) Select Case t.Job Case cBwJob.JobType.ADD_NEW_TRACKS sBwAppAddNewFilesToLibrary(t.TaskData) Case cBwJob.JobType.CAPITALIZE_FIRST_LETTER sBwAppCaptitalizeWord() Case cBwJob.JobType.FIND_NEW_TRACKS_FROM_HDD sBwAppFindNewTracksFromHDD() Case cBwJob.JobType.INITIALIZE_ITUNES sBwAppLoadItunes() Case cBwJob.JobType.LOAD_ALBUMS sBwAppFillTrackCount() Case cBwJob.JobType.RATINGS_BACKUP sBwAppRatingsBackup() Case cBwJob.JobType.RATINGS_RESTORE sBwAppRatingsRestore() Case cBwJob.JobType.RECOVER_TAGS sBwAppRecoverTags() Case cBwJob.JobType.REPLACE_WORD sBwAppReplaceTextInTags() Case cBwJob.JobType.VALIDATE_LIBRARY If mAppInfo.ApplicationState = AppInfo.SoftwareCycle.FINAL Then sBwAppValidateLibrary() Else Try sBwAppValidateLibrary() Catch ex As Exception mErrOccured = True Dim lErrLog As New System.IO.StreamWriter(mFilePathErrorLog) lErrLog.WriteLine(String.Format("{0}", ex.Message)) lErrLog.WriteLine(String.Format("{0}", ex.StackTrace)) lErrLog.Close() End Try End If End Select 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:
Private Sub sPerformTask(Function myFunction) If mAppInfo.ApplicationState = AppInfo.SoftwareCycle.FINAL Then Try Call myFunction() Catch ex As Exception mErrOccured = True Dim lErrLog As New System.IO.StreamWriter(mFilePathErrorLog) lErrLog.WriteLine(String.Format("{0}", ex.Message)) lErrLog.WriteLine(String.Format("{0}", ex.StackTrace)) lErrLog.Close() End Try Else Call myFunction() End If End Sub
So I can call this like
VB Code:
sPerformTask(sBwAppReplaceTextInTags())VB Code:
sPerformTask(sBwAppReplaceTextInTags())VB Code:
sPerformTask(sBwAppReplaceTextInTags())
Etc...
I hope I am making myself clear.
Any help would be much appreciated.
Thanks,
McoreD
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
and a property in the class by which I could set up the delegateVB Code:
Public delBufferFull As BufferFull
In the form, I made the subVB Code:
Public WriteOnly Property SetupBufferFullDelegate() As BufferFull Set(ByVal Value As BufferFull) delBufferFull = Value 'load with address of sub in parent form End Set End Property
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:
Private Sub HandleBufferFull(ByVal BufferNumber As Int32) byDataArray = objInputToBuffer.ReadBuffer ProcessSoundData() 'data to progress bars End Sub
Then, from within the class, I called the sub in the formVB Code:
objInputToBuffer.SetupBufferFullDelegate = AddressOf HandleBufferFull 'inform class where to call when data is ready
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. ;)VB Code:
delBufferFull.Invoke(k) 'tell the parent form so it will read data from array
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.
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.In your case you could even do this:VB Code:
#If BETA Then 'Write beta code here. #Else 'Write final code here. #End IfThat 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.VB Code:
#If BETA Then Try #End If 'Write actual code here. #If BETA Then Catch ex As Exception End Try #End If
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:what you actually need to do is this:VB Code:
Private Sub Method1() MessageBox.Show("Hello World") End Sub Private Sub Method2() Method3(Method1) End Sub Private Sub Method3(myMethod As Sub) Call myMethod End SubMethodInvoker 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:
Private Sub Method1() MessageBox.Show("Hello World") End Sub Private Sub Method2() Method3(New MethodInvoker(AddressOf Method1)) End Sub Private Sub Method3(ByVal myMethod As MethodInvoker) myMethod.Invoke() End SubThere are several things to note here:VB Code:
Private Delegate Function QuestionAsker(ByVal question As String) As DialogResult Private Function AskQuestion(ByVal question As String) As DialogResult Return MessageBox.Show(question, "Yes or No", MessageBoxButtons.YesNo, MessageBoxIcon.Question) End Function Private Sub Method2() Method3(New QuestionAsker(AddressOf AskQuestion)) End Sub Private Sub Method3(ByVal myMethod As QuestionAsker) Dim result As DialogResult = DirectCast(myMethod.Invoke("Are you male?"), DialogResult) Select Case result Case Windows.Forms.DialogResult.Yes MessageBox.Show("You are male.") Case Windows.Forms.DialogResult.No MessageBox.Show("You are female.") End Select End Sub
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.
Sorry for my duplicate post: http://www.vbforums.com/showthread.php?t=449681
Not my style and will not happen again.
Thanks,
McoreD