JohnnyGr wrote:
I have heard theres a new way to start threads with parameters in
framework 2.0, does anyone know how to do that?
this is what i need to do...
Start a thread that executes some stuff, in this case it does gets all
files from a directory. then i need to update the GUI with information
from the thread...
the thread should be started with a parameter, in this case its a string
that contains the path to the files...
Appriciate any code examples.
Thanks in advance.
AFAIK, the new way for working with threads (and the easiest one, as it
seems) is given by the BackgroundWorke r control. You add one of these
beasts to your Form and call your threaded method from its DoWork
event. When the thread finishes, the BackgroundWorke r raises an event
on the UI thread where you can get any results back from threaded
method:
'--------------------------------------------------------
Function ScanFiles(ByVal Path As String) As String()
'--------------------------------------------------------
Dim Result() As String
'... Scan the file system ...'
Return Result
End Function
'--------------------------------------------------------
Private Sub AsyncScanFiles_ DoWork( _
ByVal Sender As System.Object, _
ByVal e As System.Componen tModel.DoWorkEv entArgs) _
Handles AsyncScanFiles. DoWork
'--------------------------------------------------------
'We're running on a secondary thread
Dim Path As String = CType(e.Argumen t, String)
e.Result = ScanFiles(Path)
End Sub
'--------------------------------------------------------
Private Sub AsyncScanFiles_ RunWorkerComple ted( _
ByVal sender As Object, _
ByVal e As System.Componen tModel.RunWorke rCompletedEvent Args _
) Handles AsyncScanFiles. RunWorkerComple ted
'--------------------------------------------------------
'We're running on the UI thread
If e.Error IsNot Nothing Then
'handle any exception raised in the thread
ElseIf Not e.Cancelled Then
Dim Result() As String = CType(e.Result, String())
'...Use the returned file list...'
End If
End Sub
In the above example, I added a BackgroundWorke r control to the form
and named it AsyncScanFiles. Somewhere in my code I called the
control's RunWorkerAsync method, passing the path as an Object
parameter:
AsyncScanFiles. RunWorkerAsync( Path)
Simple, eh? :-D
Another approach would be to handle it yourself. The Thread class
allows for passing a single parameter of type Object to the target
method. The problem is getting a result back. Besides, you must not
access the UI from your secondary thread. See, the UI should only be
acessed from the main thread (actually, from the thread that created
the UI elements, which is the main thread of the app).
The "protocol" I use is similar to the backgroundworke r control. I use
auxiliary methods to lauch the thread and to get results delivered to
the UI.
Imports SysThread = system.Threadin g
'--------------------------------------------------------
Function ScanFiles(ByVal Path As String) As String()
'--------------------------------------------------------
Dim Result() As String
'... Scan the file system ...'
Return Result
End Function
'--------------------------------------------------------
Private Sub AsyncScanFiles( ByVal PathString As Object)
'--------------------------------------------------------
Dim Path As String = CType(PathStrin g, String)
Dim Result() As String = ScanFiles(Path)
ScanFilesDone(R esult)
End Sub
'... somewhere in my code
Dim T As New SysThread.Threa d(AddressOf AsyncScanFiles)
T.Start(Path)
Notice that the method AsyncScanFiles passes the result to another
auxiliary method, called ScanFilesDone. It's this method that brings
the result back to the UI thread. You can detect if you're outside the
UI thread by checking the Form's InvokeRequired property (this property
is actually inherited from the Control class). If InvokeRequired
returns true, it means that the current thread is other than the main
thread, and so you *must not* touch the UI from there. You need to
transfer control to the main thread using the Form's BeginInvoke method
(which is also inherited from the Control class).
Private Delegate Sub ScanFilesHandle r(ByVal Result() As String)
'...
Sub ScanFilesDone(B yVal Result() As String)
If Me.InvokeRequir ed Then
'We're still out of the UI thread
Dim T As New ScanFilesHandle r(AddressOf ScanFilesDone)
Dim Params() As Object = {Result}
Me.BeginInvoke( T, Params)
Else
'We're in the UI thread.
'By this time, the calling thread is long gone
For Each Item As String In Result
'Show the files in the UI
Next
End If
End Sub
In ScanFilesDone, the Form's InvokeRequired tells me that we're not on
the main thread. ScanFilesDone calls itself again, this time
indirectly, by using the Form's BeginInvoke method. To do this I had to
declare a new delegate type, which I called ScanFilesHandle r. This is
because the Form's BeginInvoke method requires a typed delegate as
parameter.
HTH.
Regards,
Branco.