2

我有这个功能:

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

我在这里调用这个函数:

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

我得到的异常是: invalidOperationException 跨线程操作无效:控件'Form1'从创建它的线程以外的线程访问

例外是在 NudgeMe() 中的行:

this.Left = rnd;

这条线被涂成绿色。

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: 
4

5 回答 5

3

您只能与创建它的线程中的控件(或窗体)进行交互。您的异常被抛出,因为您正在与第二个线程的表单进行交互。

要解决您所拥有的问题,请查看表单上的 Invoke 或 BeginInvoke 方法——它们允许您传递将在表单线程上执行的委托(这称为“编组”)

更好:与其进入一段时间然后睡觉,不如使用计时器。如果您在 Windows 窗体命名空间中使用计时器,它将为您处理编组问题,因此您甚至不需要使用 Invoke

于 2012-08-08T15:12:49.413 回答
1

您需要将修改同步到表单的SynchronizationContext.

修改位于与 UI 线程不同的线程中 - 因此是跨线程异常。

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

_sync.Send((state) => {
  // code to modify UI objects
}
于 2012-08-08T15:12:26.717 回答
1
this.Invoke((MethodInvoker) delegate {
    this.Left = rnd;
});
于 2012-08-08T15:12:37.183 回答
1

发生错误是因为 UI 组件必须在创建它们的同一线程上进行操作。您的后台工作人员在不同的线程中运行。

您可以使用InvokeRequired和回调来让 UI 线程完成工作。

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;
    }
}
于 2012-08-08T15:13:00.740 回答
0

从后台线程更改 UI 线程是一个很大的禁忌。您可以删除直接从后台工作人员访问 UI 的代码,或者看看这个问题......

如何从 C# 中的另一个线程更新 GUI?

于 2012-08-08T15:12:21.940 回答