2011-12-14 8 views
0

私は1つのメインウィンドウフォームを持ち、そのフォーム内にはアプリケーションの異なるスクリーンを表すカスタムコントロールがあります。このコントロールの子コントロールにアクセスしたいです。私がここに来ていないことがあります...時々私はこのエラーを受け取ります:C#windowsはカスタムコントロールのクロススレッド操作をフォームします

Cross-thread operation not valid: 
Control 'lblText' accessed from a thread 
other than the thread it was created on.

時にはすべてが正常に動作します。私はcompletelly理由は理解していない...おそらく何か外部デバイス(MEI BillAcceptor)は、(Form1クラス内の)イベントのコントロールに変更を行います...私は単純なコードを書くことができます...

//user control 
public partial class Screen2 : UserControl 
{ 
    public void changeValue(string txt) 
    { 
     lblText.Text = txt; 
    } 
} 

及び方法の特定のイベントが発祥したときchangeValueがForm1のから呼び出された...

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
     BillAcceptor.SomeBillAcceptorEvent += 
      new SomeBillAcceptorEventHandler(changeText); 
    } 

    private void changeText(object sender, EventArgs args) 
    { 
     _screen2.changeValue("some text"); 
    } 
} 

だから、最も厄介な事は時々すべてが実際に動作するということです...だから私の質問は "ここでInvokeを使用する必要がありますか? "またはどのように私はアプリケーションにあまり変更でこれを解決するのです...

答えて

1

はい、そのメソッドが別のスレッドから呼び出される可能性がある場合は、Invokeを使用する必要があります。

trueの場合はthis.InvokeRequired()を確認し、falseの場合は通常の呼び出しを行います。

0

これが原因thread unsafe call

に発生したあなただけのプログラム

チェックthisリンクでの安全な呼び出しをスレッドにする必要があります。

3

あなたのハンドラで。このようなことをしてください。

 if (this.InvokeRequired) 
     { 
      Invoke(new MethodInvoker(() => 
      { 
       _screen2.changeValue("some text"); 
      })); 
     } 
     else 
     { 
      _screen2.changeValue("some text"); 
     } 

メインUIスレッド以外の別のスレッドでイベントが発生していると思います。

0

短い答えははいです。あなたはInvokeを使用する必要があります。 this question and its accepted answer if you need detailsを参照してください。

ところで、例外がスローされるのは、ちょっとタイミングが崩れるからです。あなたは現在、競争状態に陥っていることもあります。

ところで、ここでは、このようなもののためのかなり便利なパターンです。

  1. フォームの値を独自のプライベートvoidメソッドに設定するすべてのコードをリファクタリングします。
  2. この新しい方法では、InvokeRequiredを呼び出します。 trueを返す場合は、Invokeを呼び出して、現在のメソッドを渡して、そのメソッドに戻ります。 falseを返した場合は、先に進んで変更を加えます。
  3. イベントハンドラからこの新しいメソッドを呼び出します。たとえば、

private void ChangeScreen2() { 
    if (this.InvokeRequired) { 
     this.Invoke(new MethodInvoker(ChangeScreen2)); 
    } 
    else { 
     _screen2.changeValue("some text"); 
    } 
} 

private void changeText(object sender, EventArgs args) 
{ 
    ChangeScreen2(); 
} 

アイデアは、あなたがそう必要であれば、常に自分自身をInvokeRequiredのチェックから始まり、常にInvokeこれらのメソッドにフォームを変更するすべてのコードを隔離することであること。このパターンは.NET 1.0以降で動作します。ちょっとしたアプローチについては、this questionへの受け入れられた回答を参照してください。これは.NET 3.0以降で動作します。

関連する問題