I'm new to the world of threading, but a few aspects of an app I'm working on require me to use a BackgroundWorker control to prevent the UI freezing up while it's doing some file operations.
What I'm trying to do is update a couple of form labels from within the BackgroundWorker. Having never worked with this before I very quickly discovered that I can't access controls that weren't created within the same thread, so after a bit of research I've implemented the following code that seems to make everything work:
Private Delegate Sub DelegateUpdateStatus(ByVal statusText As String, ByRef currentFile As String)
Private Sub UpdateStatus(ByVal statusText As String, ByVal currentFile As String)
If InvokeRequired Then
Invoke(Sub() LblStatus.Text = statusText)
Invoke(Sub() LblCurrentFile.Text = currentFile)
Else
LblStatus.Text = statusText
LblCurrentFile.Text = currentFile
End If
End Sub
Thing is though, I have no understanding of what this code is doing, or why it's required.
I've done a bit of research but I've not done any real work with this kind of thing, and most articles I've read assume some kind of prior knowledge.
The three main things I looking to gain an understanding of:
- Why this code is required (as in, why the controls can't be accessed directly from the BackgroundWorker)
- What a delegate is, and when the use of it is required
- What the Invoke method does, and what I'm checking for with InvokeRequired
As said, threading is still quite a foreign concept, so any answers in plain English would be really helpful - thanks!
EDIT: Thanks for the responses so far everybody. I've done some further reading, and I'm wondering if I'm going about this the right way. The reason I'm using a BackgroundWorker is to ensure that the UI remains responsive while I'm performing file operations. The issue is, I still need to wait until the BackgroundWorker has done its job so I can return a boolean indicating the success of the operation. There's ways to work around this, but from my reading, having to wait for a BackgroundWorker to complete its work is defeating the purpose of using it in the first place. So, what's the best way to go about preventing the UI from locking up?
InvokeRequired
asks 'Am I on the right thread?', if so carry on, else I need a delegate - in your code you see a lambda SubThe other way this could work is to direct the result to a diff Sub routine(where the delegate has crossed over to the correct thread), but here we are able to run a Sub inside the Invoke method itself - just a simpler way to do it.
A delegate is required any time you use a separate thread to do work async.
Invoke - MSDN
BackgroundWorker is another way to have thread and make thread-safe call from it. on
ProgressChanged
, andRunWorkerCompleted
you can make thread-safe calls to UIDelegate is just reference to the method
Control.Invoke(Delegate)
Control.InvokeRequired
And Why we need it all these stuffs . From msdn document it is clarified :
OK, well done for getting so far.
Lets start with point 1.
From How to: Make Thread-Safe Calls to Windows Forms Controls
So, as you can see, you need to ensure that when changing the state of a control, it is done in a threadsafe manner.
Now, the property Control.InvokeRequired checks whether the code you are executing is on a different thread to the one that originally created the control.
If it is, we need some way to call code on that original thread.
For this reason you need to use Control.Invoke Method to execute such code on the original thread.
Now the thing is, you need to tell that thread what it should be executing, and this is done using the delegate.
Now, the last thing I would recommend is that you look at what the differences between Delegates, Anonymous Delegates, Anonymous Methods and Lamda expressions.