Background worker not updating UI

Hi,

I was wondering if someone can help. I have attached the following code to help show you the problem.
I am trying to update the UI from the background worker without much luck:

Snippet ID=8162067 on Form1 where the UI control is
Snippet ID=8162090 in clsPart that runs as part of the DoWorkEventArgs

I run Form1.BackgroundWorker1.ReportProgress(0, x) that passes a structure back to Form1.
In debug mode the values look ok:

Console.WriteLine(CStr(CType(e.UserState, UpdatePart02.clsPart.Status).intCurrent))

But the following does not update the UI:
Me.txtCurrent.Text = CStr(CType(e.UserState, UpdatePart02.clsPart.Status).intCurrent)

Regards,

Ross

Imports System.ComponentModel

Public Class clsPart
    Private conEpr As New clsConnection
    Private objPart As Epicor.Mfg.BO.Part
    Private ds As Epicor.Mfg.BO.PartDataSet
    ' Public Event ProgressChanged As ProgressChangedEventHandler

    Public Structure Status
        Public intCurrent As Integer
        Public intTotal As Integer
    End Structure



    Public Sub LoadParts(ByVal dt As DataTable)
        Dim booFound As Boolean = False
        Dim intErrors As Integer = 0

        For i As Integer = 0 To dt.Rows.Count - 1
            ds = New Epicor.Mfg.BO.PartDataSet
            'Try
            objPart = New Epicor.Mfg.BO.Part(conEpr.getConnection)
            booFound = objPart.PartExists(dt.Rows(i).Item("PartNum"))

            ' If booFound = False Then
            'objPart.GetNewPart(ds)
            Try
                Dim x As New Status
                ds = objPart.GetByID(dt.Rows(i).Item("PartNum"))
                Console.WriteLine(dt.Rows(i).Item("PartNum") & " " & i & " OF: " & dt.Rows.Count - 1)

                x.intCurrent = i
                x.intTotal = dt.Rows.Count - 1
                Form1.BackgroundWorker1.ReportProgress(0, x)
                ds.Tables("Part").Rows(0).Item("InActive") = True
                ds.Tables("PartPlant").Rows(0).Item("ProcessMRP") = False
                objPart.Update(ds)
                x = Nothing
            Catch ex As Exception
                Console.WriteLine(ex.Message)
            End Try

            ds = Nothing
            objPart = Nothing
        Next i


    End Sub
    Public Function AmINull(ByVal nv As Object) As String
        If IsDBNull(nv) = True Then
            Return ""
        Else
            Return nv
        End If
    End Function
    Public Function ConvertYesNO(ByVal strVar As String) As Boolean
        Select Case strVar
            Case "YES"
                Return True
            Case "NO"
                Return False
        End Select

    End Function

End Class

Open in new window

Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        objPart.LoadParts(dt)
        objExcel = Nothing
        objPart = Nothing
    End Sub


    Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
        Console.WriteLine(CStr(CType(e.UserState, UpdatePart02.clsPart.Status).intCurrent))
        Console.WriteLine(CStr(CType(e.UserState, UpdatePart02.clsPart.Status).intTotal))
        
Me.txtCurrent.Text = CStr(CType(e.UserState, UpdatePart02.clsPart.Status).intCurrent)
        Me.txtTotal.Text = CStr(CType(e.UserState, UpdatePart02.clsPart.Status).intTotal) 
Me.Refresh
    End Sub

Open in new window

ross13Asked:
Who is Participating?
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Change:

    Private Sub ReportProgress(ByVal sender As Object) Handles objPart.LoadingProgress
        Me.txtCurrent.Text = CStr(CType(sender, UpdatePart02.clsPart.Status).intCurrent)
        Me.txtTotal.Text = CStr(CType(sender, UpdatePart02.clsPart.Status).intTotal)
    End Sub

To:

    Private Sub ReportProgress(ByVal sender As Object) Handles objPart.LoadingProgress
        Me.BackgroundWorker1.ReportProgress(0, sender)
    End Sub

Now your ProgressChanged() event will fire:

    Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
        Dim
        Me.txtCurrent.Text = CStr(CType(sender, UpdatePart02.clsPart.Status).intCurrent)
        Me.txtTotal.Text = CStr(CType(sender, UpdatePart02.clsPart.Status).intTotal)
    End Sub
0
 
Éric MoreauSenior .Net ConsultantCommented:
have you set the WorkerReportsProgress property to true?
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Is Form1 the startup object?...or is it being loaded from a different from with the "new" keyword?
0
Cloud Class® Course: Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

 
CodeCruiserCommented:
Add an

Application.DoEvents

at the end of progress changed event handler.
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
If DoEvents() fixes it then the background thread is raising too many progress events.  Consider raising progress every XXX iterations (like 50?...you'll have to experient), or raise them based on a time interval (like once a second).
0
 
ross13Author Commented:
Hi,

I have you set the WorkerReportsProgress property to true.
Form1 is the startup object.

I have also tried adding Application.DoEvents to the end of BackgroundWorker1_ProgressChanged.

Still no joy.

Cheers,

Ross
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
I would make a custom event for your "clsPart" class:

     Public Class clsPart

         Public Event LoadingProgress(ByVal progress As clsPart.Status)

     End Class

Then, instead of directly invoking ReportProgress(), raise the event from your class:

     Me.LoadingProgress(x)

When you instantiate "clsPart", use AddHandler() to wire up the event in the main form (or declare it as "WithEvents" and use Handles).

When the event is received in the main form, then call ReportProgress() from there.
0
 
ross13Author Commented:
Hi,

Thanks for that. I am not sure that i have done this correctly I gave it a go by adding the following:

Public Class clsPart
     Public Event LoadingProgress(ByVal progress As clsPart.Status)


     Public Sub LoadParts(ByVal dt As DataTable)
        RaiseEvent LoadingProgress(x)
     End Sub
End Class

Within my main form:

Public Class Form1
WithEvents objPart As New clsPart

    Private Sub ReportProgress(ByVal sender As Object) Handles objPart.LoadingProgress
        Me.txtCurrent.Text = CStr(CType(sender, UpdatePart02.clsPart.Status).intCurrent)
        Me.txtTotal.Text = CStr(CType(sender, UpdatePart02.clsPart.Status).intTotal)

    End Sub

End Class

The ReportProgress does fire but i receive the following error message when trying to set the values in report progress:

Cross-thread operation not valid: Control 'txtCurrent' accessed from a thread other than the thread it was created on.

Cheers,

Ross
0
 
vbighamCommented:
It sounds like you need to marshal back to the UI thread, since winForms are not thread safe and neither their controls, you will need to run the update code on the same thread that created the controls.

A common method for doing that in this scenario would probably look something like this:
 
Private Sub ReportProgress(ByVal sender As Object) Handles objPart.LoadingProgress
    If Not Me.InvokeRequired Then
        UpdateStatus(CType(sender, UpdatePart02.clsPart.Status))

    Else
        Me.Invoke(AddressOf UpdateStatus, CType(sender, UpdatePart02.clsPart.Status))
    End If
End Sub


Private Sub UpdateStatus(ByVal prtStatus As UpdatePart02.clsPart.Status)
    If prtStatus Is Nothing Then Return

    Me.txtCurrent.Text = CStr(prtStatus.intCurrent)
    Me.txtTotal.Text = CStr(prtStatus.intTotal)
End Sub

Open in new window

0
 
ross13Author Commented:
Thanks for that. Now working ok.

Cheers,

Ross
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.