delegates....confused

meofcourse

New member
Joined
Jan 10, 2010
Messages
4
Programming Experience
Beginner
First off, I am quite confused....

I have done some googling and found the following links with regards to using delegates to change values in the main thread:
Shabdar.org - Free open source projects
CodeProject: Prevent 'cross-thread operation not allowed' exception through reflection. Free source code and programming help
Cross-thread operation not valid: .NET Cross Threading To Update Form Control « DataBatrix

I think I understand where that approach is coming from. Now let me explain what I am doing:

I am writing an app that rips a cd and uploads it to a website. I would like it threaded so that my cancel button is accessible as well as my progress bars are updated. So basically this is what I have set up:

Main Form contains a drop down menu with a list of cd drives.
When the start button is clicked, a new thread is started which rips the tracks from the cd.
In order for the new thread to be able to rip the cd, it needs to know what drive to rip from. However, that information is in the main thread, and not accessible to my new thread. All the examples I found all show how to assign values to a different thread, but not how to get values from another thread.

Here is my existing code:

VB.NET:
Private Sub cmdRip_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdRip.Click
        
        Dim t As System.Threading.Thread
        t = New System.Threading.Thread(AddressOf RipCDTracks)
        t.Start()
Exit Sub
VB.NET:
Private Delegate Sub SetControlValueCallback(ByVal oControl, ByVal propName, ByVal propValue)
VB.NET:
 Private Sub RipCDTracks()
        If Me.cboDevice.InvokeRequired Then
           <<------This is where I am having issues.  How do I get the value of me.cbodevice.selectedindex when I am in another thread? ------>>
        Else
            drivenum = Me.cboDevice.SelectedIndex
        End If
.....Rest of code to actually rip the tracks
End Sub
 
tomorrow

Thanks for the link. In all my searches, I was only able to find examples like the first two posts. The third post looks like what I want. I don't have time to try it today, so I'll try it tomorrow night and post back.

-meofcourse
 
Jmcilhinney's thread on delegates is amazingly informative and easy to follow along.

I'll admit that when I was learning this topic that was where I ended up.
 
still a little confused

When returning a value via a delegate function (the 3rd example listed), how does the line:
VB.NET:
text = CStr(Me.TextBox1.Invoke(New GetTextBoxTextInvoker(AddressOf GetTextBoxText)))

know what property of the TextBox1 to return? (eg. the text property rather than the readonly property)

From my very basic understanding, shouldn't this look more like this?

VB.NET:
text = CStr(Me.TextBox1.Invoke(New GetTextBoxInvoker(AddressOf GetTextBoxText), Me.TextBox1, Text))

-meofcourse
 
When returning a value via a delegate function (the 3rd example listed), how does the line:
VB.NET:
text = CStr(Me.TextBox1.Invoke(New GetTextBoxTextInvoker(AddressOf GetTextBoxText)))

know what property of the TextBox1 to return? (eg. the text property rather than the readonly property)
That particular line DOESN'T know what property of the TextBox to return. What that line does is create a GetTextBoxTextInvoker delegate that refers to the GetTextBoxText method. The delegate gets invoked by the Invoke method, the delegate invokes the GetTextBoxText method, the GetTextBoxText method returns a value, the delegate returns that value, the Invoke method returns that value and that value gets assigned to the 'text' variable. There is nothing to do with any properties of the TextBox in that line. It's THIS line that knows what property of the TextBox to return:
VB.NET:
text = Me.TextBox1.Text
As you can see, it's returning the Text property of the TextBox.

What you need to understand is that, under these circumstances, your GetTextBoxText method is getting called twice. The first time it is called on the worker thread, so it enters the If block. There it essentially calls itself again, via the delegate. The second time it is called on the UI thread so it enters the Else block. In the Else block it accesses the control directly and gets the appropriate property value and returns it. That return value is then used back in the first call and finally returned to your original caller on the worker thread.
 
As I said, under these circumstances, the GetTextBoxText method gets called twice: once on the worker thread and once on the UI thread.
VB.NET:
Private Delegate Function GetTextBoxTextInvoker() As String

Private Function GetTextBoxText() As String
    Dim text As String

    If Me.TextBox1.InvokeRequired Then
        text = CStr(Me.TextBox1.Invoke(New GetTextBoxTextInvoker(AddressOf GetTextBoxText)))
    Else
        text = Me.TextBox1.Text
    End If

    Return text
End Function
In an attempt to make it clearer, let's break it up into two separate methods: one that gets called on the worker thread and one that gets called on the UI thread:
VB.NET:
Private Delegate Function GetTextBoxTextInvoker() As String

Private Function GetTextBoxText[COLOR="Red"]1[/COLOR]() As String
    Dim text As String

    text = CStr(Me.TextBox1.Invoke(New GetTextBoxTextInvoker(AddressOf GetTextBoxText[COLOR="Red"]2[/COLOR])))

    Return text
End Function

Private Function GetTextBoxText[COLOR="Red"]2[/COLOR]() As String
    Dim text As String

    text = Me.TextBox1.Text

    Return text
End Function
As you can see, one method does the invoking to cross the thread boundary while the other one accesses the control. My original code simply combines the two into a single method that will do both, depending on which thread it's called on.
 
Two thumbs up!

What you need to understand is that, under these circumstances, your GetTextBoxText method is getting called twice. The first time it is called on the worker thread, so it enters the If block. There it essentially calls itself again, via the delegate. The second time it is called on the UI thread so it enters the Else block. In the Else block it accesses the control directly and gets the appropriate property value and returns it. That return value is then used back in the first call and finally returned to your original caller on the worker thread.

Thank you! :D That makes everything clear. Its like the lightbulb in my head just turned on.

Thanks again.
 
Back
Top