スレッド間の操作が無効です: コントロールは、それが作成されたスレッド以外のスレッドからアクセスされました。質問する

スレッド間の操作が無効です: コントロールは、それが作成されたスレッド以外のスレッドからアクセスされました。質問する

シナリオがあります。(Windows Forms、C#、.NET)

  1. いくつかのユーザー コントロールをホストするメイン フォームがあります。
  2. ユーザー コントロールは大量のデータ操作を実行するため、UserControl_Loadメソッドを直接呼び出すと、ロード メソッドの実行中は UI が応答しなくなります。
  3. これを克服するために、別のスレッドにデータをロードします(既存のコードをできるだけ変更しないようにします)
  4. 私はバックグラウンド ワーカー スレッドを使用しました。このスレッドはデータを読み込み、完了すると、作業が完了したことをアプリケーションに通知します。
  5. ここで、実際の問題が発生しました。すべての UI (メイン フォームとその子ユーザー コントロール) は、プライマリ メイン スレッドで作成されました。ユーザー コントロールの LOAD メソッドでは、ユーザー コントロール上の一部のコントロール (テキスト ボックスなど) の値に基づいてデータを取得しています。

疑似コードは次のようになります。

コード 1

UserContrl1_LoadDataMethod()
{
    if (textbox1.text == "MyName") // This gives exception
    {
        //Load data corresponding to "MyName".
        //Populate a globale variable List<string> which will be binded to grid at some later stage.
    }
}

例外は

クロススレッド操作が無効です: コントロールは、それが作成されたスレッド以外のスレッドからアクセスされました。

これについてもっと知るためにグーグルで調べたところ、次のコードを使うという提案が見つかりました。

コード2

UserContrl1_LoadDataMethod()
{
    if (InvokeRequired) // Line #1
    {
        this.Invoke(new MethodInvoker(UserContrl1_LoadDataMethod));
        return;
    }

    if (textbox1.text == "MyName") // Now it won't give an exception
    {
    //Load data correspondin to "MyName"
        //Populate a globale variable List<string> which will be binded to grid at some later stage
    }
}

しかし、やはり振り出しに戻ってしまったようです。アプリケーションは再び応答しなくなりました。これは、条件の 1 行目の実行によるものと思われます。ロード タスクは、私が生成した 3 番目のスレッドではなく、親スレッドによって再び実行されます。

私がこれを正しく認識したか、間違って認識したかは分かりません。

これを解決するにはどうすればよいですか?また、Line#1 if ブロックの実行の影響は何ですか?

状況は次のとおりです。コントロールの値に基づいて、グローバル変数にデータをロードしたいです。子スレッドからコントロールの値を変更したくありません。子スレッドからそれを実行するつもりはありません。

したがって、対応するデータをデータベースから取得できるように、値にのみアクセスします。

ベストアンサー1

に従ってPrera​​k K のアップデートコメント(削除済み):

質問を適切に提示できなかったようです。

状況は次のとおりです。コントロールの値に基づいて、グローバル変数にデータをロードしたいです。子スレッドからコントロールの値を変更したくありません。子スレッドからそれを実行するつもりはありません。

したがって、対応するデータをデータベースから取得できるように、値にのみアクセスします。

必要な解決策は次のようになります。

UserContrl1_LOadDataMethod()
{
    string name = "";
    if(textbox1.InvokeRequired)
    {
        textbox1.Invoke(new MethodInvoker(delegate { name = textbox1.text; }));
    }
    if(name == "MyName")
    {
        // do whatever
    }
}

コントロールのスレッドに戻る前に、別のスレッドで重要な処理を実行してください。例:

UserContrl1_LOadDataMethod()
{
    if(textbox1.text=="MyName") //<<======Now it wont give exception**
    {
        //Load data correspondin to "MyName"
        //Populate a globale variable List<string> which will be
        //bound to grid at some later stage
        if(InvokeRequired)
        {
            // after we've done all the processing, 
            this.Invoke(new MethodInvoker(delegate {
                // load the control with the appropriate data
            }));
            return;
        }
    }
}

おすすめ記事