Avatar of rutledgj
rutledgj
 asked on

vb.net How to update UI from task

Ok. So I'm trying to use the task stuff to do parallel programming. I can't figure out how to update a gui label from a task.  

I have Downloads class with method DownloadPatientData(V as Vendor)    Vendor is a class to hold data.

in main form I have:

 While VendorQueue.Count > 0
                Dim v As Vendor = Nothing
                If VendorQueue.TryDequeue(v) = True Then
                    threadCount += 1
                    Console.WriteLine("Processing Org " & v.Org)
                    v.DrFirstVersion = DrFirstVersion
                    Dim d As New Downloads
                    d.ThreadName = "t" & CStr(threadCount)
                    Dim t As Task = Task.Factory.StartNew(Sub() d.DownloadPatientData(v))        
                End If
            End While

So over in the DownloadPatientData method how can I write back to the gui label (lblStatus)?

In regular threading you could add a event handler.  What do you do here?
Visual Basic.NET

Avatar of undefined
Last Comment
Mike Tomlinson

8/22/2022 - Mon
Mike Tomlinson

Make your Downloads class raise a custom event with the text to display in the label:  
Public Class Downloads

    Public Event Status(ByVal txt As String)

    Private Sub Foo()
        RaiseEvent Status("blah...") ' <-- just an example
    End Sub

End Class

Open in new window


Now, in your form, create a method to receive the event and update the label:  
Public Class Form1

    Private Sub dld_Status(ByVal txt As String)
        If Me.InvokeRequired Then
            Me.Invoke(New Action(Of String)(AddressOf dld_Status), New Object() {txt})
        Else
            Me.lblStatus.Text = txt
        End If
    End Sub

End Class

Open in new window


Finally, use AddHandler() to wire up the event when the instance of Downloads is created:  
...
        Dim d As New Downloads
        d.ThreadName = "t" & CStr(threadCount)
        AddHandler d.Status, AddressOf dld_Status
        Dim t As Task = Task.Factory.StartNew(Sub() d.DownloadPatientData(v))

Open in new window

rutledgj

ASKER
Well this compiles but the code never gets to the  Me.lblStatus.Text = txt
It does the Me.Invoke section but nothing else.
nepaluz

The method to recieve the event inthe main form should be:
Public Class Form1

    Private Sub dld_Status(ByVal txt As String)
        If Me.InvokeRequired Then
            Me.Invoke(New Action(Of String)(AddressOf dld_Status), New Object() {txt})
        End If
        Me.lblStatus.Text = txt
    End Sub

End Class

Open in new window

I started with Experts Exchange in 2004 and it's been a mainstay of my professional computing life since. It helped me launch a career as a programmer / Oracle data analyst
William Peck
rutledgj

ASKER
that doesn't work either. Never gets to lblstatus.text = txt
rutledgj

ASKER
I have also noticed that raising the event from the DownloadPatientData method, even though it doesn't update the label, prevents the application from closing.  It gets stuck in the task.waitall call. Removing the raiseevent allows it to complete as normal.

There must be a different way to update the gui using tasks.

ASKER CERTIFIED SOLUTION
Mike Tomlinson

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
rutledgj

ASKER
This is the complete code in the main form.  When the tasks complete I close the app.

 While VendorQueue.Count > 0
                Dim v As Vendor = Nothing

                If VendorQueue.TryDequeue(v) = True Then
                    threadCount += 1
                    Console.WriteLine("Processing Org " & v.Org)
                    v.DrFirstVersion = DrFirstVersion
                    Dim d As New Downloads
                    d.ThreadName = "t" & CStr(threadCount)
                    d.MyVendor = v
                    AddHandler d.ThreadFinished, AddressOf ThreadUpdateHandler
                    '  lstTasks.Add(Task.Factory.StartNew(Sub() d.DownloadPatientData()))
                    Dim t As New Task(Sub() d.DownloadPatientData())
                    t.Start()
                    lstTask.Add(t)
                End If
            End While

            Task.WaitAll(lstTasks.ToArray)

            Application.Exit()





I understand what you are saying. A catch 22.  So what is the alternative?
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
SOLUTION
Log in to continue reading
Log In
Sign up - Free for 7 days
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.