2

I have this function:

public void NudgeMe()
        {


            int xCoord = this.Left;
            int yCoord = this.Top;


            int rnd = 0;


            Random RandomClass = new Random();

            for (int i = 0; i <= 500; i++)
            {
                rnd = RandomClass.Next(xCoord + 1, xCoord + 15);
                this.Left = rnd;
                rnd = RandomClass.Next(yCoord + 1, yCoord + 15);
                this.Top = rnd;
            }
            this.Left = xCoord;
            this.Top = yCoord;
        }

And im calling this function here:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            while (true)
            {

                if ((worker.CancellationPending == true))
                {
                    e.Cancel = true;
                    break;
                }
                else
                {
                    if (tempCpuValue >= (float?)nud1.Value || tempGpuValue >= (float?)nud1.Value)
                    {
                        soundPlay = true;
                        blinking_label();
                        NudgeMe();
                    }
                    else
                    {
                        soundPlay = false;
                        stop_alarm = true;

                    }
                    cpuView();
                    gpuView();
                    Thread.Sleep(1000);
                }
            }
        }

The exception im getting is: invalidOperationException Cross-thread operation not valid: Control 'Form1' accessed from a thread other than the thread it was created on

The exception is on the line in the NudgeMe() :

this.Left = rnd;

The line is painted in green.

System.InvalidOperationException was unhandled by user code
  Message=Cross-thread operation not valid: Control 'Form1' accessed from a thread other than the thread it was created on.
  Source=System.Windows.Forms
  StackTrace:
       at System.Windows.Forms.Control.get_Handle()
       at System.Windows.Forms.Control.SetBoundsCore(Int32 x, Int32 y, Int32 width, Int32 height, BoundsSpecified specified)
       at System.Windows.Forms.Form.SetBoundsCore(Int32 x, Int32 y, Int32 width, Int32 height, BoundsSpecified specified)
       at System.Windows.Forms.Control.SetBounds(Int32 x, Int32 y, Int32 width, Int32 height, BoundsSpecified specified)
       at System.Windows.Forms.Control.set_Left(Int32 value)
       at HardwareMonitoring.Form1.NudgeMe() in D:\C-Sharp\HardwareMonitoring\HardwareMonitoring\Hardwaremonitoring\Form1.cs:line 782
       at HardwareMonitoring.Form1.backgroundWorker1_DoWork(Object sender, DoWorkEventArgs e) in D:\C-Sharp\HardwareMonitoring\HardwareMonitoring\Hardwaremonitoring\Form1.cs:line 727
       at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)
       at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)
  InnerException: 
user1544479
  • 927
  • 5
  • 13
  • 21

5 Answers5

3

You can only interact with a control (or form) from the thread that created it. Your excepiton is being thrown because you are interacting with the form from a second thread.

To fix what you have, look at the Invoke or BeginInvoke methods on the form -- they allow you to pass a delegate that will be executed on the form's thread (this is called "marshalling")

Better: Rather than enter a While and sleep, use a timer. If you use the timer in the Windows Forms namespace, it will handle the marshalling issue for you so you won't even need to use Invoke

JMarsch
  • 21,484
  • 15
  • 77
  • 125
1

You need to synchronize the modifications to the Form's SynchronizationContext.

The modifications are in a different thread than the UI thread - thus the Cross-Thread exception.

// get a reference to the form's sync-context
SynchronizationContext _sync = SynchronizationContext.Current;

_sync.Send((state) => {
  // code to modify UI objects
}
IAbstract
  • 19,551
  • 15
  • 98
  • 146
1
this.Invoke((MethodInvoker) delegate {
    this.Left = rnd;
});
Otiel
  • 18,404
  • 16
  • 78
  • 126
1

The error occurs because UI components must be manipulated on the same thread in which they were created. Your background worker is operating in a different thread.

You can use InvokeRequired and a callback to get the UI thread to do the work.

public void NudgeMe() {
    if( this.InvokeRequired ) {
        Action callBack = NudgeMe;
        this.Invoke( callBack );
    } else {

        int xCoord = this.Left;
        int yCoord = this.Top;


        int rnd = 0;


        Random RandomClass = new Random();

        for( int i = 0; i <= 500; i++ ) {
            rnd = RandomClass.Next( xCoord + 1, xCoord + 15 );
            this.Left = rnd;
            rnd = RandomClass.Next( yCoord + 1, yCoord + 15 );
            this.Top = rnd;
        }
        this.Left = xCoord;
        this.Top = yCoord;
    }
}
James
  • 2,445
  • 2
  • 25
  • 35
  • 1
    You probably shouldn't be putting this entire thing into an `invoke` call. It's best to do as little as possible when invoking because the UI thread is being blocked when doing so. In particular, for this case, the `for` loop is making a number of incremental changes, but since there is only one `Invoke` call they are all rendered after they are each done. – Servy Aug 08 '12 at 15:50
0

Making changes to the UI thread from a background thread is a big no-no. You can either remove the code that is directly accessing the UI from your background worker, or take a look at this question...

How to update the GUI from another thread in C#?

Community
  • 1
  • 1
Kevin DiTraglia
  • 25,746
  • 19
  • 92
  • 138