I have probably read and tried a hundred different ways to do this, and I can't take it any longer or wrap my head around it. I am new to multi-threading and usually make the UI process the code. I found the error of my ways as my program grew. Now I have classes and a thread that does not lag-out/freeze the main UI.
From within that class I am trying to update a label on the main form. (with what progress has been made)
The relevant code is as follows:
There is a label on the main form called UpdateLabel
A button on the main form:
Private Sub btnStartMenu_Click(sender As Object, e As EventArgs) Handles
btnStartMenu.Click
Call New Action(AddressOf setupthread1).BeginInvoke(Nothing, Nothing)
End Sub 'creates a new thread which runs great, not freezing the UI!
Private Sub setupthread1() 'this code is still on the main form
'all of the label updates work fine from here.
StartMenu_Folders.startMenuFolders() 'This is the class that gets called
'from the main form
Public Class StartMenu_Folders
Public Shared Sub startMenuFolders()
frmMenu.UpdateLabel(frmMenu.lblLogoff, "...Updating Label text") 'this code is probably incorrect? Though the updatelabel DOES get
'successfully called
'This next part is back on the main form.
Public Sub UpdateLabel(ByVal lblLogoff As Label, ByVal Value As String)
If lblLogoff.InvokeRequired Then
Dim dlg As New UpdateLabelDel(AddressOf UpdateLabel)
dlg.Invoke(lblLogoff, Value)
Else
lblLogoff.Text = Value
End If
End Sub
ANY help would be appreciated, it is probably a 2 second explanation from one of you senior coders out there.
At this point it looks like the threads are running perfectly with no freezing, but the label just is not updating. . Thank you. I really appreciate it!
========================== Update EDIT to Code from information provided.
From viewers like YOU! Cue Reading rainbow music
'This is all on Main form 'frmMenu'
'Improved way of starting the class in a new thread
Private Sub btnStartMenu_Click(sender As Object, e As EventArgs) Handles btnStartMenu.Click
Dim t As Task = Task.Run(Sub()
StartMenu_Folders.startMenuFolders()
End Sub)
End Sub
Public Delegate Sub UpdateLabelInvoker(ByVal text As String)
Public Sub UpdateLabel(ByVal text As String)
If Me.lblLogoff.InvokeRequired Then
Me.lblLogoff.Invoke(New UpdateLabelInvoker(AddressOf UpdateLabel), _
text)
MsgBox("invoked")
Else
Me.lblLogoff.Text = text
MsgBox("DIDNT invoke")
End If
End Sub
'This is all in the class
Public Class StartMenu_Folders
Public Shared Sub startMenuFolders()
frmMenu.UpdateLabel("testtestest")
End Sub
End Class
'This code is still creating a separate instance of frmMenu I believe.
'I'm not sure how to target the right thread to update the label.
'I've tried me.UpdateLabel("testtesttest") to no avail.
If anyone knows how to do that, that would be great! Everything else is working swimmingly. It's a shame that updating a label on a form from another thread is the hardest hoop I've had to jump through for this program in the months I've been working on it.
You don't call Invoke
on the delegate and pass the Label
. You call Invoke
on the Label
and pass the delegate:
lblLogoff.Invoke(dlg, Value)
See my explanation and examples here.
EDIT:
OK, I think I've got a handle on it this time. This:
Public Class StartMenu_Folders
Public Shared Sub startMenuFolders()
frmMenu.UpdateLabel(frmMenu.lblLogoff, "...Updating Label text") 'this code is probably incorrect? Though the updatelabel DOES get
'successfully called
becomes this:
Public Class StartMenu_Folders
Public Shared Sub startMenuFolders(menuForm As frmMenu)
menuForm.UpdateLabel("...Updating Label text")
This:
StartMenu_Folders.startMenuFolders()
becomes this:
StartMenu_Folders.startMenuFolders(Me)
This:
Public Sub UpdateLabel(ByVal lblLogoff As Label, ByVal Value As String)
If lblLogoff.InvokeRequired Then
Dim dlg As New UpdateLabelDel(AddressOf UpdateLabel)
dlg.Invoke(lblLogoff, Value)
Else
lblLogoff.Text = Value
End If
End Sub
becomes this:
Public Sub UpdateLabel(ByVal Value As String)
If lblLogoff.InvokeRequired Then
Dim dlg As New UpdateLabelDel(AddressOf UpdateLabel)
lblLogoff.Invoke(dlg, Value)
Else
lblLogoff.Text = Value
End If
End Sub
In future, please don't post code from two different classes in the same block as it has caused confusion here. If you have two classes then post code from them in two different blocks.