1

メイン ウィンドウ フォームが 1 つあり、そのフォーム内にアプリケーションのさまざまな画面を表すカスタム コントロールがあります。このコントロールの子コントロールにアクセスしたい。ここで得られないことがあります...時々、このエラーが発生します:

クロススレッド操作が無効です:
スレッドからアクセスされたコントロール 'lblText'
作成されたスレッド以外。

しかし、すべてがうまくいくこともあります。エラーの理由が完全にはわかりません...おそらく、コントロールに変更を加えるイベント(Form1クラス内)を持つ外部デバイス(MEI BillAcceptor)の何か...簡単なコードを書きましょう...

//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 を使用する必要がありますか?」または、アプリケーションへの変更を少なくしてこれを解決するにはどうすればよいですか...

4

4 に答える 4

4

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

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

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

于 2011-12-14T15:23:02.067 に答える
2

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

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

于 2011-12-14T15:23:27.953 に答える
0

これが原因で発生しますthread unsafe call

プログラムではスレッドセーフな呼び出しのみを行う必要があります

このリンクを確認してください。

于 2011-12-14T15:20:13.210 に答える
0

簡単に言えば、「はい」です。Invoke を使用する必要があります。詳細が必要な場合は、この質問とその受け入れられた回答を参照してください

ちなみに、例外が時々スローされる理由は、タイミングにあります。あなたは現在、運が良い時もあればそうでない時もある競争状態にあります。

ところで、これはこの種の非常に便利なパターンです。

  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 以降で機能します。さらにきちんとしたアプローチについては、この質問に対する受け入れられた回答を参照してください。これは、.NET 3.0 以降で動作します。

于 2011-12-14T15:27:12.643 に答える