2011-01-02 1 views
1

擬似コード:背景ワーカーイベント

form1 
{ 
    int i; 
    label1; 

    Add() 
    { 
    i++; 
    label1 = i.ToString(); //#ErrorLine 
    } 

    backgroundworker worker; 

    worker_DoWork() 
    { 
    FileGuard guard = new FileGuard(); 
    guard.FileKilled += guard.KillH(Add); 
    guard.StarGuarding(); //there is system watcher inside 
          //this guard and some processing code 
          //that will fire event FileKilled(); 

    } 
} 

StartGuarding()労働者が をcompleatedされますが、イベントがあるときFileKilledがクロススレッド#ErrorLine

私はライン上でこのエラーをゴス

を解雇した呼び出しのafer operation not valid:作成されたスレッド以外のスレッドからアクセスされる 'form1'を制御します。

答えて

4

これはイベント自体とは関係ありませんが、別のスレッドからUIコントロールにアクセスしているという事実とは関係ありません。 Windowsフォームでは、メインのUIスレッド以外のスレッドからUIを操作することはできません。

InvokeRequiredを使用して、UIにアクセスできないスレッドにいるかどうかを確認し、必要に応じてInvokeを使用してUIスレッドでコードを実行できます。 (それらは自動的にUIスレッドにマーシャリングされているので)あなたがProgressChangedとRunWorkerCompletedEventsから直接UIを使用することができます

private void DoStuffWithGUI() 
{ 
    if (InvokeRequired) 
    { 
     Action work = DoStuffWithGUI; 
     Invoke(work); 
    } 
    else 
    { 
     // Your normal logic 
    } 
} 

:それは次のようになります。しかし、DoWork内で行うすべての作業(したがって、作業の一部として発生させるすべてのイベント)は別のスレッドで実行され、Invokeを使用してUIスレッドにマーシャリングする必要があります。 MSDNからBackgroundWorkerのために:

あなたの DoWorkイベントハンドラで 任意のユーザインターフェイスオブジェクトを操作しないように注意する必要があります。代わりに、 は、ProgressChangedイベントと RunWorkerCompletedイベントを通じて、ユーザーインターフェイス と通信します。

+1

BackgroundWorkerはUIを変更できませんか?私はそうだと思いました。 – jgauffin

+1

いいえ、BackgroundWorkerはメインUIとは異なるスレッドで実行されますが、これは 'BackgroundWorker'の主な目的です。 – driis

+0

私は、GUIアップデートを処理できるようになるためには、いくつかの魔法の同期があるという印象を受けました。しかし、私はMSDNでこのテキストを見つけました。DoWorkイベントハンドラ内のユーザーインターフェイスオブジェクトを操作しないように注意する必要があります。代わりに、ProgressChangedおよびRunWorkerCompletedイベントのソースを通じてユーザーインターフェイスに通信します。http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx – jgauffin

0

やWPFは、したがって、あなたの問題、彼らが作成されたフォーム以外からのオブジェクト:

BackgroundWorker用として、あなたはGUI更新を処理するためにイベントを使用する必要があります。

ディスパッチャを使用してUIスレッドにアップデートを送信します。

あなたがWinFormsまたはWPFを使用しているかどうかを詳しく知ることができれば、より多くの情報を提供することができます。

0

コントロールを作成したスレッド以外のスレッドから変更することはできません。 InvokeRequiredプロパティとInvokeメソッドを使用して、UIスレッドへの呼び出しをバックグラウンドスレッドからマーシャリングする必要があります。

private readonly _lockObject = new Object(); 

Add() 
{ 
    lock(_lockObject) 
    { 
     i++; 
     if(label1.InvokeRequired) 
      Invoke(new Action(() => label1 = i.ToString())); 
     else 
      label1 = i.ToString(); 
    } 
} 

この例外を避けるために、lockは必須ではありません。メソッドをスレッドセーフにするために追加されました。