0

What am I doing wrong here?

my plan is to change the label text property from a different thread without getting the "Cross-thread operation not valid" exception.

    private void button1_Click(object sender, EventArgs e)
    {
        Thread thread1 = new Thread(new ThreadStart(ChangeTime));
        thread1.Start();
    }

    delegate void SetTimeDelegate();

    private void ChangeTime()
    {
        while (true)
        {
            if (lbl1.InvokeRequired)
            {
                SetTimeDelegate setTime = new SetTimeDelegate(ChangeTime);
                lbl1.Invoke(setTime);


            }
            else
            {
                lbl1.Text = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss tt");
                Thread.Sleep(1000);
            }
        }
    }
John Saunders
  • 160,644
  • 26
  • 247
  • 397
RollRoll
  • 8,133
  • 20
  • 76
  • 135
  • It looks like you aren't invoking. Honestly, I can't tell what you are trying to do here. – JDB Sep 13 '12 at 01:28
  • I'm trying to change the text from a label from the form to current datetime called from a new thread – RollRoll Sep 13 '12 at 01:35
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders Sep 13 '12 at 02:20

1 Answers1

3

To update a UI control from a different thread you need to call the BeginInvoke or Invoke method. You can use the specific control's methods or the form's.

Your original code has infinite recursion. You are Invoking correctly except your delegate is calling the same method. Create a separate method for updating the label with the time and have the delegate cll that new method.

private bool _IsShuttingDown = false;

private void ChangeTime()
{
   while (!_IsShuttingDown)
   {
      if (lbl1.InvokeRequired)
      {
         SetTimeDelegate setTime = new SetTimeDelegate(UpdateTimeLabel);
         lbl1.Invoke(setTime);
         Thread.Sleep(1000);
      }
      else
      {
         UpdateTimeLabel();
         Thread.Sleep(1000);
      }
   }
}

private void UpdateTimeLabel()
{
   lbl1.Text = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss tt");
}

protected override void OnClosing(CancelEventArgs e)
{
   _IsShuttingDown = true;
   base.OnClosing(e);
}

I also added a field on the form to exit the loop when the form is closing or else weird things happen.

My original code:

if (lbl1.InvokeRequired)
{
    lbl1.Invoke((Action)(() => lbl1.Text = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss tt")));
    Thread.Sleep(1000);
}
Shane Charles
  • 299
  • 1
  • 5
  • It worked perfectly, I didn't fully understand this cast to Action – RollRoll Sep 13 '12 at 01:58
  • @EdwinSnts I changed the code to better fit your original code. All cast to Action does is make it act like a Delegate. – Shane Charles Sep 13 '12 at 02:04
  • this is very helpful, i used to declare a delegate to and call it whenever i need to update a control from a different thread, but that is also useful if you are trying to update more than one control – sameh.q May 28 '13 at 05:49