0

毎回1つの条件を確認するタイマーがあり、条件が確認された場合にポップアップフォームを1回だけ表示します。すべてのインスタンスを並行して検証したいので、parallel.for を使用しましたが、「クロススレッド操作が無効です: コントロール 'CameraViewVS' は、それが作成されたスレッド以外のスレッドからアクセスされました。」というエラーが表示されます。行内 " frm.WindowState = FormWindowState.Normal;"

これは私のコードです:

public void timer1_Tick(object source, EventArgs e)               
{
    Parallel.For(0, nbre, l =>
        {
            cameraInstanceList[l].Start();
            if (cameraInstanceList[l].MoveDetection == true)
            {
                //show the the form S once 
                foreach (Form S in Application.OpenForms)
                {
                    var frm = S as Formes.CameraViewVS;
                    if (frm != null && frm.IP == cameraInstanceList[l].adresse)
                    {
                        cameraInstanceList[l].MoveDetection = false;
                        frm.WindowState = FormWindowState.Normal;
                        frm.Activate();
                        return;
                    }
                }

                f1 = new Formes.CameraViewVS(cameraInstanceList[l],
                adresseIPArray[l]);
                f1.Show(this);

            }

        }               
        );
4

2 に答える 2

0

WinFormオブジェクトインスタンスのほとんどのプロパティは、それらが作成されたスレッドからアクセスする必要があります。Control.InvokeRequiredプロパティを使用して、コントロール(またはフォーム)のInvokeメソッドを使用してUIスレッドでコードを実行する必要があるかどうかを判断できます。

また、ほとんどのWinFormコントロールを、スレッドプールスレッドではなく、メインUIスレッドで作成することもお勧めします。WinFormsアプリケーションでは、を使用しSynchronizationContextて、フォームの作成などの一部のコードがUIスレッドで呼び出されるようにすることができます。

編集:動きが検出された後にメソッドが戻らないように変更されました。

public void timer1_Tick(object source, EventArgs e)                         
{          
    // assume this is being called on the UI thread, and save the thread synchronization context
    var uiContext = SynchronizationContext.Current;

    Parallel.For(0, nbre, l =>          
        {          
            while (true)
            {
                Thread.Sleep(250);  // <--- sleep for 250 ms to avoid "busy" wait

                cameraInstanceList[l].Start();          
                if (cameraInstanceList[l].MoveDetection == true)          
                {       
                    // capture instances used in closures below
                    var cameraInstance = cameraInstanceList[l];
                    var ipAdresse = adresseIPArray[l];

                    //show the the form S once                             
                    foreach (Form S in Application.OpenForms)                            
                    {
                        var frm = S as Formes.CameraViewVS; 
                        if (frm != null)
                        {
                            // create delegate to be invoked on form's UI thread.
                            var action = new Action(() =>
                                {
                                    if (frm.IP == cameraInstance.adresse) 
                                    { 
                                        cameraInstance.MoveDetection = false; 
                                        frm.WindowState = FormWindowState.Normal; 
                                        frm.Activate(); 
                                    }
                                };

                            if (frm.InvokeRequired)
                                frm.Invoke(action);  
                            else
                                action();

                            continue; // <--- go back to the top of the while loop
                                      //      and wait for next detection
                        }
                    }

                    // create delegate to create new form on UI thread.
                    var createNewFormCallback = new SendOrPostCallback((o) =>
                        {
                            f1 = new Formes.CameraViewVS(cameraInstance, ipAdresse); 
                            f1.Show(this);  
                        };    

                    // and invoke the delegate on the ui thread
                    uiContext.Send(createNewFormCallback, null); 
                }            
            } 
        }
        );
}
于 2012-07-12T22:17:21.423 に答える
0

トーマスは正しい答えに非常に近いです。なぜなら、すべてのコントロールは別のスレッドで実行されるからです。コントロール スレッドで使用されているリソースのコンテキスト切り替え用のコードを書くだけでよいのです。このための多くの機能があることを心配しないでください。 Cシャープで。BeginInvokeとInvokeを使用するだけで、問題を解決できることを願っています。古いコードブロックの代わりにこれを書いてください..

                 var action = new Action(() =>
                            {
                                if (frm.IP == cameraInstance.adresse) 
                                { 
                                    cameraInstance.MoveDetection = false; 
                                    frm.WindowState = FormWindowState.Normal; 
                                    frm.Activate(); 
                                }
                            };

                        if (frm.InvokeRequired)
                            frm.BeginInvoke(action);  
                        else
                            frm.Invoke(action);
于 2012-07-14T21:18:38.113 に答える