Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VB.NET Delegates and Invoke - can somebody explain these to me?

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?

like image 417
synoptica Avatar asked Jun 27 '13 04:06

synoptica


2 Answers

InvokeRequired asks 'Am I on the right thread?', if so carry on, else I need a delegate - in your code you see a lambda Sub

 Invoke(Sub() LblStatus.Text = statusText)

The 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

like image 131
OneFineDay Avatar answered Oct 17 '22 19:10

OneFineDay


  1. BackgroundWorker is another way to have thread and make thread-safe call from it. on ProgressChanged, and RunWorkerCompleted you can make thread-safe calls to UI

  2. Delegate is just reference to the method

Control.Invoke(Delegate)

Executes the specified delegate on the thread that owns the control's underlying window handle.

Control.InvokeRequired

Gets a value indicating whether the caller must call an invoke method when making method calls to the control because the caller is on a different thread than the one the control was created on.

And Why we need it all these stuffs . From msdn document it is clarified :

If you have two or more threads manipulating the state of a control, it is possible to force the control into an inconsistent state. Other thread-related bugs are possible, such as race conditions and deadlocks. It is important to make sure that access to your controls is performed in a thread-safe way.

So for safety reasons we have to implement this, otherwise our worker threads and UI thread may both try to access the data member at once, and it will wreak havoc on our application . So instead of disabling it and having a chance crash possibility of your application, you should better use thread-safe patterns .

like image 39
qwr Avatar answered Oct 17 '22 21:10

qwr