PHP User Warning: fetch_template() calls should be replaced by the vB_Template class. Template name: bbcode_highlight in ..../includes/functions.php on line 4197

PHP User Warning: fetch_template() calls should be replaced by the vB_Template class. Template name: bbcode_highlight in ..../includes/functions.php on line 4197

PHP User Warning: fetch_template() calls should be replaced by the vB_Template class. Template name: bbcode_highlight in ..../includes/functions.php on line 4197
[RESOLVED] How to update a form control from another thread-VBForums
Results 1 to 10 of 10

Thread: [RESOLVED] How to update a form control from another thread

  1. #1

    Thread Starter
    Lively Member
    Join Date
    Nov 2013
    Posts
    106

    Resolved [RESOLVED] How to update a form control from another thread

    In another post I was trying to update a form listbox control from a thread using the synchronousContext method but was not able to do so successfully. I decided to try doing that using the delegate method and I am having trouble with that too. The following code updates the listbox okay from the Form1_Load routine. In the delegate, it successfully posts a msgbox with the correct information, but the following line (Form1.lbStatus.Items.Add(msg)) does not update the listbox and it does not generate an error. Can someone help me understand what is wrong or better still guide me on how updating a form control from another thread is supposed to be done?

    Thanks

    Code:
    Imports System.Threading
    Public Class Form1
        Dim thr As New Thread(New ThreadStart(AddressOf MyThread))
    
        ' Set up a delegate
        Dim dc As New DelegateClass
        Dim mydc As MyDelegate = AddressOf dc.StatusUpdate
    
        Class DelegateClass
            Sub StatusUpdate(ByVal msg As String)
                MsgBox(msg)                         ' this works fine
                Try
                    Form1.lbStatus.Items.Add(msg)   ' this does not update the listbox
                Catch ex As Exception
                    MessageBox.Show(ex.Message)
                End Try
            End Sub
        End Class
    
        Delegate Sub MyDelegate(ByVal msg As String)
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            thr.Start()
            lbStatus.Items.Add("From Form1_Load")   ' this works
        End Sub
    
        Private Sub MyThread()
            mydc.Invoke("From MyThread")
            thr.Abort()
        End Sub
    
        Private Sub Quit_Click(sender As Object, e As EventArgs) Handles Quit.Click
            Application.Exit()
        End Sub
    End Class

  2. #2
    Bad man! ident's Avatar
    Join Date
    Mar 2009
    Location
    Cambridge
    Posts
    5,313

    Re: How to update a form control from another thread

    Of course, the form_load event will update the control. It is being performed on the UI thread. By simply calling a class a DelegateClass is not going tomagically invoke back to the UI thread.

    Code:
    me.invoke(sub() .....)
    http://www.vbforums.com/showthread.p...Worker-Threads

  3. #3
    .NUT jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    102,601

    Re: How to update a form control from another thread

    For a start, that code is horribly convoluted. Other things to note:
    Code:
    MsgBox(msg)                         ' this works fine
    No it doesn't work fine. MsgBox is supposed to display a message dialogue modally but modal dialogues are thread-specific so you'll find that that dialogue actually doesn't prevent you accessing the main form.
    Code:
    Form1.lbStatus.Items.Add(msg)   ' this does not update the listbox
    It actually does update the ListBox that you are referring to in the code. The problem is that that is not the ListBox you're looking at. Follow the Blog link in my signature and read my post on Default Form Instances.
    Code:
    mydc.Invoke("From MyThread")
    Calling Invoke on a delegate simply executes the method that it refers to, which is done on the current thread. That's the wrong Invoke method to execute a method on the UI thread. Follow the CodeBank link in my signature and check out my thread on Accessing Controls From Worker Threads.

    There's no need for you to declare your own delegate types or that nested class. If you follow the pattern I provide in the CodeBank then your code can look like this:
    vb.net Code:
    1. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    2.     AddItemToListBox("From Form1_Load")
    3.  
    4.     Dim t As New Thread(AddressOf BackgroundMethod)
    5.  
    6.     t.Start()
    7. End Sub
    8.  
    9. Private Sub BackgroundMethod()
    10.     AddItemToListBox("From BackgroundMethod")
    11. End Sub
    12.  
    13. Private Sub AddItemToListBox(item As Object)
    14.     If ListBox1.InvokeRequired Then
    15.         ListBox1.Invoke(New Action(Of Object)(AddressOf AddItemToListBox), item)
    16.     Else
    17.         ListBox1.Items.Add(item)
    18.     End If
    19. End Sub
    That demonstrates that a method written using that pattern will work as intended regardless of the thread that it is called on. If you wanted to simplify that code based on knowledge of which thread code is executed on then it could look like this:
    vb.net Code:
    1. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    2.     ListBox1.Items.Add("From Form1_Load")
    3.  
    4.     Dim t As New Thread(AddressOf BackgroundMethod)
    5.  
    6.     t.Start()
    7. End Sub
    8.  
    9. Private Sub BackgroundMethod()
    10.     ListBox1.Invoke(Sub() ListBox1.Items.Add("From BackgroundMethod"))
    11. End Sub
    In that case, there's no method written specifically to ensure that code is executed on the UI thread but rather Invoke is either used or not, based on the fact that that code is known to be executing on a secondary thread or the UI thread.

  4. #4

    Thread Starter
    Lively Member
    Join Date
    Nov 2013
    Posts
    106

    Re: How to update a form control from another thread

    I followed the link you provided and copied the vb example into a new form project and added a textbox control named TextBox1. That example code has 2 errors. One at Me.BackgroundWorker1.RunWorkerAsync() (the message says, "BackgroundWorker1 is not a member of Form1.) The other error is in the BackgroundWorker1_DoWork sub after the handles keyword. That one says, "Handles clause requires a WithEvents variable defined in the containing type or one of its base types."

    I would like to find an example that actually works or have some indication on how to fix this particular example.

    Thanks

  5. #5

    Thread Starter
    Lively Member
    Join Date
    Nov 2013
    Posts
    106

    Re: How to update a form control from another thread

    I followed the link you provided and copied the vb example into a new form project and added a textbox control named TextBox1. That example code has 2 errors. One at Me.BackgroundWorker1.RunWorkerAsync() (the message says, "BackgroundWorker1 is not a member of Form1.) The other error is in the BackgroundWorker1_DoWork sub after the "Handles" keyword. That one says, "Handles clause requires a WithEvents variable defined in the containing type or one of its base types."

    I would like to find an example that actually works or have some indication on how to fix this particular example.

    Here is the example:
    Code:
    Imports System.Threading
    Public Class Form1
        Private Sub Form1_Load(ByVal sender As System.Object,
                           ByVal e As System.EventArgs) Handles MyBase.Load
            Threading.Thread.CurrentThread.Name = "UI Thread"
        End Sub
    
        Private Sub Button1_Click(ByVal sender As System.Object,
                              ByVal e As System.EventArgs) Handles Button1.Click
            Me.ResetTextBoxText()
    
            Me.BackgroundWorker1.RunWorkerAsync()
        End Sub
    
        Private Sub BackgroundWorker1_DoWork(ByVal sender As Object,
                                         ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            Threading.Thread.CurrentThread.Name = "Worker Thread"
    
            Me.ResetTextBoxText()
        End Sub
    
        Private Sub ResetTextBoxText()
            Debug.WriteLine(Threading.Thread.CurrentThread.Name, "ResetTextBoxText")
    
            If Me.TextBox1.InvokeRequired Then
                Me.TextBox1.Invoke(New MethodInvoker(AddressOf ResetTextBoxText))
            Else
                Me.TextBox1.ResetText()
            End If
        End Sub
    End Class

  6. #6
    .NUT jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    102,601

    Re: How to update a form control from another thread

    Quote Originally Posted by PickyBiker View Post
    I followed the link you provided and copied the vb example into a new form project and added a textbox control named TextBox1. That example code has 2 errors. One at Me.BackgroundWorker1.RunWorkerAsync() (the message says, "BackgroundWorker1 is not a member of Form1.) The other error is in the BackgroundWorker1_DoWork sub after the "Handles" keyword. That one says, "Handles clause requires a WithEvents variable defined in the containing type or one of its base types."

    I would like to find an example that actually works or have some indication on how to fix this particular example.
    And I would like it if people could follow simple instructions. The text IMMEDIATELY preceding the example you meantion says this:
    To see this in action, try creating a new project and add a Button and a TextBox to the form along with a BackgroundWorker. Now add the following code:
    You could apparently add the Button and the TextBox without a problem but decided that you could dispense with the BackgroundWorker, but then complain when the compiler tells you that there's no BackgroundWorker.

  7. #7
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    5,284

    Re: How to update a form control from another thread

    Quote Originally Posted by PickyBiker View Post
    ...
    I would like to find an example that actually works or have some indication on how to fix this particular example.
    ...
    In addition to properly following the directions for that "particular" example, I assume the two examples given in post #3 also "actually work".

  8. #8

    Thread Starter
    Lively Member
    Join Date
    Nov 2013
    Posts
    106

    Re: How to update a form control from another thread

    I never heard of a background worker and it appeared to me that it was already in the example because of the multiple references I saw in the code. After reading the responses it is now clear that a backgroundworker can be added much like a textbox, a timer, or any of a number of other controls.

    I added a backgroundworker and now have a working example to study.

    Thank you all for the helpful pointers and your patience.

  9. #9
    .NUT jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    102,601

    Re: How to update a form control from another thread

    All's well that ends well. That example just used a BackgroundWorker for simplicity too. The DoWork event is raised on a secondary thread so the event handler is executed on a secondary thread. You can use any other means to get code to execute on a secondary thread, including creating a Thread object and calling Start explicitly. That example could be changed to do that like this:
    vb.net Code:
    1. Imports System.Threading
    2. Public Class Form1
    3.     Private Sub Form1_Load(ByVal sender As System.Object,
    4.                        ByVal e As System.EventArgs) Handles MyBase.Load
    5.         Threading.Thread.CurrentThread.Name = "UI Thread"
    6.     End Sub
    7.  
    8.     Private Sub Button1_Click(ByVal sender As System.Object,
    9.                           ByVal e As System.EventArgs) Handles Button1.Click
    10.         Me.ResetTextBoxText()
    11.  
    12.         Dim t As New Thread(AddressOf DoWork)
    13.  
    14.         t.Start()
    15.     End Sub
    16.  
    17.     Private Sub DoWork()
    18.         Threading.Thread.CurrentThread.Name = "Worker Thread"
    19.  
    20.         Me.ResetTextBoxText()
    21.     End Sub
    22.  
    23.     Private Sub ResetTextBoxText()
    24.         Debug.WriteLine(Threading.Thread.CurrentThread.Name, "ResetTextBoxText")
    25.  
    26.         If Me.TextBox1.InvokeRequired Then
    27.             Me.TextBox1.Invoke(New MethodInvoker(AddressOf ResetTextBoxText))
    28.         Else
    29.             Me.TextBox1.ResetText()
    30.         End If
    31.     End Sub
    32. End Class
    The point of the example is the ResetTextBoxText method and the pattern it implements. If you call it on the UI thread then execution goes straight to the Else block and the TextBox is reset. If you call it on a secondary thread though, execution goes to the If block and the method invokes itself a second time - this time on the UI thread - and execution goes to the Else block again. The Debug.WriteLine call shows that calling the method on a secondary thread causes it to be executed twice: once on that thread and again on the UI thread.

  10. #10

    Thread Starter
    Lively Member
    Join Date
    Nov 2013
    Posts
    106

    Re: [RESOLVED] How to update a form control from another thread

    Thank you for the explanation. This is a useful model that I could have used in past projects and it will certainly be useful in current and future projects. I marked the thread RESOLVED.

    Best regards

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width