Jack Jack - 1 year ago 45
Vb.net Question

Updating UI from worker thread through delegates

For some reason invoking delegates to update to UI doesn't work for one of my threads but using different delegates to update the same controls in a slightly different way does work.

Here's the broken code, I've commented around the lines that are broken to explain

Private Sub RunBtn_Click(sender As Object, e As EventArgs) Handles RunBtn.Click
Dim transferThread As New System.Threading.Thread(AddressOf RunTransfer)
UpdateStatus("Running Transfer...")
StartTime = Date.Now

incrementProgMethod = New incrementProgDelegate(AddressOf incrementProg)
finishProgMethod = New finishProgDelegate(AddressOf finishProg)
updateStatusMethod = New updateStatusDelegate(AddressOf UpdateStatus)
writeErrorMethod = New writeErrorDelegate(AddressOf WriteError)
writeWarningMethod = New writeWarningDelegate(AddressOf WriteWarning)
writeAlertMethod = New writeAlertDelegate(AddressOf WriteAlert)
EndTransferMethod = New EndTransferDelegate(AddressOf endTransfer)


End Sub

Private Sub RunTransfer()

'(...Some work...)

For catRow = 0 To CATImportArr.Length - 1
Dim currentCATSerial, currentCATAsset As String
currentCATSerial = LCase(CATImportArr(catRow).getSerialNumber)
currentCATAsset = LCase(CATImportArr(catRow).getAssetNumber)

'This line produces this error: Unable to cast object of type 'System.String' to type 'System.Delegate'.
Invoke(updateStatusMethod("Searching " & currentCATSerial & ", " & currentCATAsset & "..."))

'This line doesn't crash but the UI label doesn't change
updateStatusMethod.Invoke("Searching " & currentCATSerial & ", " & currentCATAsset & "...")

'This line doesn't crash but the UI progress bar doesn't change

These are the methods being called through the delegates

Public Function UpdateStatus(ByRef text As String)
ParentForm.StatusLbl.Text = text
Return text
End Function

Public Sub finishProg()
ParentForm.StatusProg.Value = 100
End Sub

Answer Source

A Delegate is simply a class holding a reference to a method. You cannot pass parameters to the Delegate itself.

To pass parameters to the method you want to invoke you have to use the Control.Invoke(Delegate, Object()) overload where you pass the parameter(s) to the Invoke() method, after you've specified the delegate:

Invoke(updateStatusMethod, "Searching " & currentCATSerial & ", " & currentCATAsset & "...")

Since the second parameter of Control.Invoke(Delegate, Object()) is declared ParamArray you may keep on specifying parameters if you need to by just separating them with a comma:

Invoke(updateStatusMethod, [param1], [param2], [param3], ...)