Question

I'm developing a vb.net application who needs to do lot of background work.I have one thread different from the main thread where I visit an url to login to a website and when it finish I want to change the text of a label.I have added in the main form this (I know that is a quick code,but it's worked me very well in other applications)

Control.CheckForIllegalCrossThreadCalls = False

I also have tried the invoke method but same result. The threads are in another class that it isn't the main form class,but if a thread is in the main form class it works and if it is in another class doesn't work

Thanks

EDIT: I have just tried this:

Public Sub UpdateButton(ByVal objs() As Object)
    If Me.InvokeRequired Then
        Me.Invoke(New Action(Of Object())(AddressOf UpdateButton), objs)
        Return
    End If
    CType(objs(0), Button).Text = objs(1).ToString
End Sub

EDIT 2:

New change no success

  Public Sub UpdateButton(ByVal objs As List(Of Object))
    If CType(objs(0), Button).InvokeRequired Then
        CType(objs(0), Button).Invoke(New Action(Of List(Of Object))(AddressOf UpdateButton), objs)
        Return
    End If
    CType(objs(0), Button).Text = objs(1).ToString
End Sub

I have changed it because it gave me an error with number of elements

EDIT 3:I have seen that I haven't explained well.

I got A form called Form1 and a Module called Functions.In the module functions I defined the four threads that my application has and its functions and two functions per thread start[thread name] and stop[thread name] where I start and stop the thread.Then I put a button in the form1 and when the users clicks it calls the start function of the thread I assgined.For exameple my application has got a thread called session_starter so when the user clicks in the login button I call startSession from the button and when it finish,the last line of the function of the thread calls updatebutton from form1 and when I call it changes the text of the button,but to 0.

I have made the updatebutton the most generally possible because I got lots of button (about 30!!) and making a function for every button change is a bit slow and annoying

EDIT 4: I have made some experiments.I put a button in the Form1 and this code to the button:

Private Sub Button10_Click_1(sender As Object, e As EventArgs) Handles Button10.Click
    Button9.Text = "hi"
    Dim Evaluator = New Thread(Sub() Me.UpdateButton(Button9, "test"))
    MsgBox("Text after setting from another thread: " & Button9.Text)
    UpdateButton(Button9, "test")
    MsgBox("Text after setting from ui thread: " & Button9.Text)
End Sub

And this is what I got: Text after setting from another thread: hi Text after setting from ui thread: test

I don't know why it happens.The code i have used is this:

 Public Sub UpdateButton(ByVal btn As Button, ByVal str As String)
    If btn.InvokeRequired Then
        btn.Invoke(New Action(Of Button, String)(AddressOf UpdateButton), btn, str)
        Return
    End If
    btn.Text = str
End Sub
Was it helpful?

Solution

Simple cross thread updating:

Public Sub UpdateButton(btn As Button, text As String)
  btn.Text = text
End Sub

Usage:

'from other thread
 Me.Invoke(Sub() 
             UpdateButton(Button9, "some text")
           End Sub)

OTHER TIPS

You can't directly update the UI from a different thread than it was created on.

How to: Make Thread-Safe Calls to Windows Forms Controls

Access to Windows Forms controls is not inherently thread safe. If you have two or more threads manipulating the state of a control, it is possible to force the control into an inconsistent state. Other thread-related bugs are possible as well, including race conditions and deadlocks. It is important to ensure that access to your controls is done in a thread-safe way.

The .NET Framework helps you detect when you are accessing your controls in a manner that is not thread safe. When you are running your application in the debugger, and a thread other than the one which created a control attempts to call that control, the debugger raises an InvalidOperationException with the message, "Control control name accessed from a thread other than the thread it was created on."

You will have to use the Invoke method on the control to update the UI control.

The code below is from the link above.

' The following example demonstrates the 'Invoke(Delegate)' method of 'Control class. 
' A 'ListBox' and a 'Button' control are added to a form, containing a delegate 
' which encapsulates a method that adds items to the listbox.This function is executed 
' on the thread that owns the underlying handle of the form. When user clicks on button 
' the above delegate is executed using 'Invoke' method. 

Imports System
Imports System.Drawing
Imports System.Windows.Forms
Imports System.Threading

Public Class MyFormControl
   Inherits Form

   Delegate Sub AddListItem()
   Public myDelegate As AddListItem
   Private myButton As Button
   Private myThread As Thread
   Private myListBox As ListBox

   Public Sub New()
      myButton = New Button()
      myListBox = New ListBox()
      myButton.Location = New Point(72, 160)
      myButton.Size = New Size(152, 32)
      myButton.TabIndex = 1
      myButton.Text = "Add items in list box" 
      AddHandler myButton.Click, AddressOf Button_Click
      myListBox.Location = New Point(48, 32)
      myListBox.Name = "myListBox"
      myListBox.Size = New Size(200, 95)
      myListBox.TabIndex = 2
      ClientSize = New Size(292, 273)
      Controls.AddRange(New Control() {myListBox, myButton})
      Text = " 'Control_Invoke' example"
      myDelegate = New AddListItem(AddressOf AddListItemMethod)
   End Sub 'New 

   Shared Sub Main()
      Dim myForm As New MyFormControl()
      myForm.ShowDialog()
   End Sub 'Main

   Public Sub AddListItemMethod()
      Dim myItem As String 
      Dim i As Integer 
      For i = 1 To 5
         myItem = "MyListItem" + i.ToString()
         myListBox.Items.Add(myItem)
         myListBox.Update()
         Thread.Sleep(300)
      Next i
   End Sub 'AddListItemMethod

   Private Sub Button_Click(sender As Object, e As EventArgs)
      myThread = New Thread(New ThreadStart(AddressOf ThreadFunction))
      myThread.Start()
   End Sub 'Button_Click

   Private Sub ThreadFunction()
      Dim myThreadClassObject As New MyThreadClass(Me)
      myThreadClassObject.Run()
   End Sub 'ThreadFunction
End Class 'MyFormControl


' The following code assumes a 'ListBox' and a 'Button' control are added to a form,  
' containing a delegate which encapsulates a method that adds items to the listbox. 
Public Class MyThreadClass
   Private myFormControl1 As MyFormControl

   Public Sub New(myForm As MyFormControl)
      myFormControl1 = myForm
   End Sub 'New 

   Public Sub Run()
      ' Execute the specified delegate on the thread that owns 
      ' 'myFormControl1' control's underlying window handle.
      myFormControl1.Invoke(myFormControl1.myDelegate)
   End Sub 'Run

End Class 'MyThreadClass
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top