C# アプリケーションの開発では、UI スレッドをワーカー スレッドから分離して、インターフェイスが応答しなくなるのを防ぐことがよくあります。同時に, 作業スレッドの UI インターフェイスのコントロールを更新する必要があります.
以下にいくつかの一般的に使用されるメソッドを紹介します.
スレッド間の操作は無効です.
インターフェイスにはボタンとラベルがあります. ボタンをクリックすると, Label の値を更新するスレッドを開始します。
- private void button1_Click(オブジェクト送信者, EventArgs e)
- {
- Thread thread1 = new Thread(new ParameterizedThreadStart(UpdateLabel));
- thread1.Start("更新Label");
- }
- プライベート ボイド UpdateLabel(オブジェクト str)
- {
- this.label1.Text = str.ToString();
- }
実行後、プログラムは「"label1" を作成しなかったスレッドからアクセスして、クロススレッド操作が無効です」というエラーを報告します。
これは、.NET がスレッド間でのコントロールの呼び出しを禁止しているためです。そうしないと、誰でもコントロールを操作でき、最終的にエラーが発生する可能性があります。
次に、スレッド間でコントロールを呼び出すいくつかの方法を紹介します.
最初の方法: コンパイラがスレッド間アクセスをチェックするのを禁止します.これは最も単純な方法であり, スレッド間の競合をチェックせず, 各スレッドが混乱するのを許すのと同じです. 最後に, Label1 コントロールの値が何であるかは予測できません (この方法はお勧めしません)
- パブリック Form1()
- {
- InitializeComponent();
- // この行を追加
- Control.CheckForIllegalCrossThreadCalls = false;
- }
2 番目の方法: デリゲートと呼び出しを使用して他のスレッドからコントロールを呼び出し、コントロールの呼び出しメソッドを呼び出すと、コントロールを制御できます。たとえば、
- private void button2_Click(オブジェクト送信者, EventArgs e)
- {
- Thread thread1 = new Thread(new ParameterizedThreadStart(UpdateLabel2));
- thread1.Start("更新Label");
- }
- プライベート ボイド UpdateLabel2(オブジェクト str)
- {
- if (label2.InvokeRequired)
- {
- // コントロールの InvokeRequired プロパティ値が true の場合、それを作成する以外のスレッドがそれにアクセスしようとしていることを意味します
- Action<string> actionDelegate = (x) => { this.label2.Text = x.ToString(); };
- // また
- // Action<string> actionDelegate = delegate(string txt) { this.label2.Text = txt; };
- this.label2.Invoke(actionDelegate, str);
- }
- それ以外
- {
- this.label2.Text = str.ToString();
- }
- }
3番目の方法:デリゲートとBeginInvokeを使用して、他のスレッドからコントロールを制御します.上記のthis.label2.Invoke(actionDelegate, str);のInvokeをBeginInvokeメソッドに変更するだけです.Invoke
メソッドとBeginInvokeメソッドの違いはその
Invoke メソッドは同期で、ワーカー スレッドが完了するのを待ちます。BeginInvokeメソッドは
非同期で、ワーカー スレッドを完了するために別のスレッドを開始します。マルチスレッド タスクの .NET コントロールで実行するために使用されます。これにより、プログラマは別のスレッドでいくつかの操作を実行できます。ダウンロードやデータベース トランザクションなどの時間のかかる操作。使いやすい
- private void button4_Click(オブジェクト送信者, EventArgs e)
- {
- (BackgroundWorker bw = new BackgroundWorker()) を使用して
- {
- bw.RunWorkerCompleted += 新しい RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
- bw.DoWork += 新しい DoWorkEventHandler(bw_DoWork);
- bw.RunWorkerAsync("タンク");
- }
- }
- void bw_DoWork(オブジェクト送信者, DoWorkEventArgs e)
- {
- // これは別のスレッドで実行されるバックグラウンド スレッドです
- // 実際に作業を行うワーカー スレッドは次のとおりです
- // 時間のかかる複雑な操作をここで行うことができます
- Thread.Sleep(5000);
- e.Result = e.Argument + "ワーカー スレッドが完了しました";
- }
- void bw_RunWorkerCompleted(オブジェクト送信者, RunWorkerCompletedEventArgs e)
- {
- // この時点で、バックグラウンド スレッドは完了してメイン スレッドに戻されているため、UI コントロールを直接使用できます。
- this.label4.Text = e.Result.ToString();
- }