RollRoll
RollRoll

Reputation: 8472

Trying to change UI control property from different thread using . InvokeRequired

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);
            }
        }
    }

Upvotes: 0

Views: 3699

Answers (1)

Shane Charles
Shane Charles

Reputation: 299

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);
}

Upvotes: 3

Related Questions