21

I use a thread writing in another class for update a label. The label is contents in Winform Main class.

 Scanner scanner = new Scanner(ref lblCont);
 scanner.ListaFile = this.listFiles;
 Thread trd = new Thread(new ThreadStart(scanner.automaticScanner));
 trd.IsBackground = true;
 trd.Start();
 while (!trd.IsAlive) ;
 trd.Join();

How you can see, i pass the reference of label into constructor of the second class. In the second class(Scanner) i've a method called "automaticScanner" that should update the label with this code:

public Scanner(ref ToolStripStatusLabel _lblContatore)
{
        lblCounter= _lblContatore;
}
Thread threadUpdateCounter = new Thread(new ThreadStart(this.UpdateCounter));
threadUpdateCounter.IsBackground = true;
threadUpdateCounter.Start();
while (!threadUpdateCounter .IsAlive) ;
threadUpdateCounter.Join();

private void AggiornaContatore()
{
  this.lblCounter.Text = this.index.ToString();        
}

I've receive this error on update of label:

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

I use .net 4 with Winform C#.

Thanks a lot for answers.

News: The problem is this line:

trd.Join();

This line block my GUI and the lable was not update. There are methods to control the finish of thread and updating the label until the end? Thanks

Antonio
  • 1,181
  • 4
  • 15
  • 34
  • but... its correct call the thread in this mode? Thread trd = new Thread(new ThreadStart(scanner.scansioneAutomatica)); trd.IsBackground = true; trd.Start(); while (!trd.IsAlive) ; trd.Join(); In this mode the GUI is blocked! :S – Antonio Feb 15 '13 at 09:37
  • Include inside the class the code Action y; and the function to attend the timer elapsed event private void T_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { c++; //delegate is the expression "y = () => label1.Text = c.ToString()" label1.Invoke(y = () => label1.Text = c.ToString()); } – Antonio Leite Dec 04 '16 at 09:37

3 Answers3

54

You cannot update UI from any other thread other than the UI thread. Use this to update thread on the UI thread.

 private void AggiornaContatore()
 {         
     if(this.lblCounter.InvokeRequired)
     {
         this.lblCounter.BeginInvoke((MethodInvoker) delegate() {this.lblCounter.Text = this.index.ToString(); ;});    
     }
     else
     {
         this.lblCounter.Text = this.index.ToString(); ;
     }
 }

Please go through this chapter and more from this book to get a clear picture about threading:

http://www.albahari.com/threading/part2.aspx#_Rich_Client_Applications

adricadar
  • 9,971
  • 5
  • 33
  • 46
Igoy
  • 2,942
  • 22
  • 23
  • lblCounter does not contain a definition for InvokeRequired, same for BeginInvoke – Antonio Feb 15 '13 at 08:11
  • i dont have Label, but ToolStripStatusLabel – Antonio Feb 15 '13 at 08:25
  • IIRC, InvokeRequired exists in every control, but is PROTECTED, this is why you see it only in "your current class" (i.e.: Form, UserControl) and trying to access it on another class (ie. Label, TextBox) fails – quetzalcoatl Feb 15 '13 at 08:25
  • when i execute this code the label doesnt change... – Antonio Feb 15 '13 at 09:29
  • It should get set to value of this.index.ToString(); Please put some more code for us to help you out. – Igoy Feb 15 '13 at 09:30
  • You are calling AggiornaContatore() method only to update the Label from another thread, you dont really need to do so. You can call it directly because UI elements can be updated from UI thread. – Igoy Feb 15 '13 at 09:42
  • perfect.... i found the solution.... now the label is correct updated.. but now i want execeute code when the thread is ended.. – Antonio Feb 15 '13 at 09:45
  • Ok, you have various ways to do so, either on the method, at the end, use beginInvoke on the control to send the control for updating on the UI thread. You can also use Background Workers, execute your code on its DoWork event which executes on a ThreadPool thread, and the UI update on its RunWorkerCompleted event- which executes on the thread from where background worker was called. – Igoy Feb 15 '13 at 09:47
  • @Yogendra i've use background worker! THANKS a lot! now all function! – Antonio Feb 15 '13 at 09:59
  • work like a charm, great! – Dracarys Feb 12 '18 at 13:16
11

Use MethodInvoker for updating label text in other thread.

private void AggiornaContatore()
{
    MethodInvoker inv = delegate 
    {
      this.lblCounter.Text = this.index.ToString(); 
    }

 this.Invoke(inv);
}

You are getting the error because your UI thread is holding the label, and since you are trying to update it through another thread you are getting cross thread exception.

You may also see: Threading in Windows Forms

Habib
  • 219,104
  • 29
  • 407
  • 436