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

コントロール(またはフォーム)を操作できるのは、それを作成したスレッドからのみです。2番目のスレッドからフォームを操作しているため、excepitonがスローされています。

持っているものを修正するには、フォームのInvokeメソッドまたはBeginInvokeメソッドを確認します。これらのメソッドを使用すると、フォームのスレッドで実行されるデリゲートを渡すことができます(これは「マーシャリング」と呼ばれます)。

より良い方法:Whileを入力してスリープするのではなく、タイマーを使用します。Windowsフォーム名前空間でタイマーを使用すると、マーシャリングの問題が処理されるため、Invokeを使用する必要もありません。

于 2012-08-08T15:12:49.413 に答える
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 に答える
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 に答える
0

バックグラウンド スレッドから UI スレッドに変更を加えることは、絶対に厳禁です。バックグラウンドワーカーからUIに直接アクセスしているコードを削除するか、この質問を見てください...

C#で別のスレッドからGUIを更新するには?

于 2012-08-08T15:12:21.940 に答える