none
How to update Form from data passed from process on another thread RRS feed

  • Question

  • Hi,
     
    I am pretty new to multi threaded applications. I am trying to update a form I created with data from a wecall that retrieves information from a webpage. Essentially I send some data to a page and capture the response. I have a class library that accumulates the data needed form the web call and then creates the call and returns the desired information. The form I would like to update for the user has a self made progress bar(using different colored layered text boxes) a percentage status in the From.Text area and a current iteration of total iteration label as well as a Elapsed and Estimated time labels.

    The form works great if I call everything from the UI thread, however, it freezes, not allowing the user to minimize the form or use the Abort button I have in place until the webcall is done. The webcall is done once a week and uses thousands of inputs, a task that generally takes up to two hours. This is the reason I have the UI for the user to track the progress. I have tried using the background worker, but I can't seem to make it work properly. At this point I am using something like the below, where there is a added reference library "Process" and two Classes within the Library, "ExcelIO" and "WebCall"



    Imports System.Threading

    Public Class Form1


    Public WithEvents t As Thread

    Delegate Sub InvokeDelegate()

    Public Event VoidComplete(ByVal CI As Integer, ByVal TI As Integer)

    Private Sub btnAbort_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAbort.Click

        t.Abort()

    End Sub

    Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click

        t = New Thread(AddressOf Me.run)

        t.Start()

    End Sub



    Private
    Sub run()

        Dim xl As New Process.ExcelIO

        Dim inputArray As String(,) = xl.GetArray("C:\TEST.xls")

        Dim sResp As String(,) = BuildArray(inputArray)

        xl.GenerateReport(sVoidResp, "C:\TESTResults.xls")

    End Sub

     

    Private Function BuildArray(ByVal inputArray As String(,)) As String(,)

        Dim wc As New Process.WebCall

        Dim rtrnResultArray(0 To UBound(inputArray, 1), 0 To 1) As String

        Dim timeStart As Double = Microsoft.VisualBasic.Timer

        For i = 0 To UBound(inputArray, 1)

            Dim passArray(0 To 1) As String
                
    passArray(0) = inputArray(i, 0)
                passArray(1) = inputArray(i, 1)
        
            
    Dim ansArray(0 To 1) As String
                
    ansArray = wc.GetResponse(passArray)

                rtrnResultArray(i, 0) = ansArray(0)
                rtrnResultArray(i, 1) = ansArray(1)

            RaiseEvent VoidComplete( i, UBound(inputArray))

        Next
        
        
    Return rtrnResultArray

    End Function

     

    Private Sub VoidEventHandler(ByVal currentIteration As Integer, ByVal totalIterations As Integer) _  
    Handles MyClass.VoidComplete

        progBarB.Width = (progBarA.Width / totalIterations) * currentIteration
        Label1.BeginInvoke(New InvokeDelegate(AddressOf InvokeLabel1))

    End
    Sub

    Private Sub InvokeLabel1()

        Label1.Text = "Working"

    End Sub

    Ok so the issue is that of course the Label Updates as "Working", which was a test, I saw in some other post here that to update the controls on the UI thread you had to invoke member. The issue I'm having is that I can't pass the data I want to it. I tried

    Private Sub InvokeLabel1(ByVal current As Integer, ByVal total As Integer)

        Label1.Text = current & " of " & total

    End Sub

    but I got the error "Mehtid 'Private Sub InvokeLabel1(current As Integer, total As Integer)' does not have a signature compatible with delegate 'Delegate Sub InvokeDelegate()'.

    so I would like to know how to pass data into the form control.

    I aslo get the error 'Cross-thread operation not valid: Control 'progBarB' accessed from a thread other than the thread it was created on.' when it attempts to update the progress bar I created. I understand why it does this, but I have no idea how to have this work properly. I assume that the background worker would make this easier, but I don't know the proper way to use it.
    I am self taught on VB, which I have been using for five years, but pretty new to .NET, less than three months using it. Any help is greatly appreciated in this matter. Thanks in advance.

    Tuesday, October 7, 2008 4:44 PM

Answers

  • thanks for the replies. I have tried to use the background worker, and I just havent gotten it to pass all of the detail I need. using the invoke method however, I have been able to get this to work.  i have discovered the problem that cleared things up alot for me.  when I create the thread  t = New Thread(AddressOf Run) , this is a pointer to the actual routine when I start it with t.Start() , inside the parentheses is where I pass the parameters i.e. t.Start(500, 300) or whatever. I am now able to use this to update the forms controls. It is quite a bit of code, but the end result works great. Thanks for the replies.
    • Marked as answer by jamesm1983 Tuesday, October 7, 2008 9:58 PM
    Tuesday, October 7, 2008 9:58 PM

All replies

  • Threading can get complex real quick and difficult to debug.  I really suggest the BackgroundWorker until you become highly proficient using threads and delegates.  With the BackgroundWorker, you have an Object which can contain anything you wish to pass from the UI thread to the worker thread, and you have an Object which can contain anything you wish to pass from the worker thread to the UI thread.  If you solve your current problem with a BackgroundWorker, you'll remember it the next time you need to use a thread.  If you solve it with threads and delegates, the complexity of the solution will prevent you from remembering the details and you'll have to retrace and relearn most of the steps the next time.
    • Edited by JohnWein Tuesday, October 7, 2008 7:15 PM
    Tuesday, October 7, 2008 7:11 PM
  • Hi ginismo,
    when you need update your progressbar, you need to do that in Invoke method, which changes UI in UI thread.
    You can pass data to your delegate as private members of your class, when delegate can still access them.

    regards

    Martin Kunc
    Tuesday, October 7, 2008 7:34 PM
  • thanks for the replies. I have tried to use the background worker, and I just havent gotten it to pass all of the detail I need. using the invoke method however, I have been able to get this to work.  i have discovered the problem that cleared things up alot for me.  when I create the thread  t = New Thread(AddressOf Run) , this is a pointer to the actual routine when I start it with t.Start() , inside the parentheses is where I pass the parameters i.e. t.Start(500, 300) or whatever. I am now able to use this to update the forms controls. It is quite a bit of code, but the end result works great. Thanks for the replies.
    • Marked as answer by jamesm1983 Tuesday, October 7, 2008 9:58 PM
    Tuesday, October 7, 2008 9:58 PM