|
-
Jan 26th, 2007, 02:03 PM
#1
Thread Starter
Fanatic Member
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.
-
Jan 26th, 2007, 02:26 PM
#2
Thread Starter
Fanatic Member
-
Jan 27th, 2007, 07:32 PM
#3
Addicted Member
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:
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
-
Jan 27th, 2007, 09:32 PM
#4
Thread Starter
Fanatic Member
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:
Public delBufferFull As BufferFull
and a property in the class by which I could set up the delegate
VB 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
In the form, I made the sub
VB Code:
Private Sub HandleBufferFull(ByVal BufferNumber As Int32)
byDataArray = objInputToBuffer.ReadBuffer
ProcessSoundData() 'data to progress bars
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:
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:
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.
-
Jan 27th, 2007, 09:51 PM
#5
Addicted Member
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.
-
Jan 27th, 2007, 09:53 PM
#6
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:
#If BETA Then
'Write beta code here.
#Else
'Write final code here.
#End If
In your case you could even do this:
VB Code:
#If BETA Then
Try
#End If
'Write actual code here.
#If BETA Then
Catch ex As Exception
End Try
#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:
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 Sub
what you actually need to do is this:
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 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:
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
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.
-
Jan 27th, 2007, 10:15 PM
#7
Addicted Member
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|