6

WinForms(3.5)を使用して.NETアプリケーションを構築しています。

最近、新しい機能を追加しましたが、特定のコントロールにアクセスすると奇妙な動作が発生し始めました。問題は、一部のUIコントロールアクセスが単に実行を停止したことでした(例外は見られませんでした)。

(WinDbgを使用して)綿密な調査を行ったところ、コントロールがThreadPoolスレッドから更新されていることに気付き、CrossThreadMessagingExceptionがスローされました。

私の質問は-そのような行動を回避する方法について何か良い習慣はありますか?

非常に面倒ですが、UIコントロールにアクセスするすべてのコードの場所をControl.Invokeメソッドで囲むことはおそらく不可能です。

Invokeを使用すべきではない「安全な」コードにコードを分割するにはどうすればよいですか?

4

1 に答える 1

9

アプリケーションがマルチスレッド化されるように設計されている場合、クロススレッド化発生する可能性があるため、InvokeRequired を使用してチェックする必要があり、UI スレッドで re-Invoke() 自体を呼び出しているメソッドを持つか、例外をスローする必要があります。コードが不適切に使用されていることを示します。特定の状況では InvokeRequired が false になることに注意してください (主に、ウィンドウにハンドルがないか、破棄されている/破棄されている場合)。このような状況を回避する最善の方法は、ウィンドウの初期化プロセスで Load() イベント ハンドラーより前にスレッドを開始しないことと、ウィンドウによって作成されたバックグラウンド スレッドをキャンセルし、それらが閉じるのを待つことによって Closing() イベントを処理することです。

アプリケーションがマルチスレッド化されていない (BackgroundWorkers、TPL 操作、BeginInvoke()ing デリゲートまたは Start()ing スレッドを設定していない) 場合は、必要ありません。ただし、InvokeRequired の呼び出しは非常に安価です (その背後にあるロジックは、基本的に、WinAPI 関数 GetThreadId と GetWindowThreadProcessId が同じ値を返すことを確認することです)。そのため、プログラムが再構築されてマルチスレッド化されることが予想される場合、呼び出されるメソッドの次のパターンは単純です。実装するのに十分です:

//no return value, no parameters; ShowWindow(), HideWindow(), etc
//Understand that many built-in control methods are not virtual and so you can't 
//override them to do this; you must either hide them or ensure the caller is
//checking for cross-threading.
public void MyWindowMethod()
{
   if(InvokeRequired)
      this.Invoke(new Action(MyWindowMethod));
   else
   {
      //main logic
   }
}

//Input but no return; SetTitle("My Title")
public void MyWindowMethod2(string input)
{
   if(InvokeRequired)
      this.Invoke(new Action<string>(MyWindowMethod2), input);
   else
   {
      //main logic
   }
}

//inputs and outputs; custom methods, advanced graphics
public string MyWindowMethod3(string input)
{
   if(InvokeRequired)
      return (string)(this.Invoke(new Func<string, string>(MyWindowMethod3), input));

   //No else required; the return makes it redundant
   //main logic   
}
于 2012-08-20T19:17:42.097 に答える