C#クロススレッド呼び出しコントロール

4809 ワード

C#のアプリケーション開発では、UIスレッドとワークスレッドを分離し、インタフェースの応答停止を防止することがよくあります.また、UIインタフェースのコントロールをワークスレッドで更新する必要があります.
いくつかの一般的な方法を紹介します

スレッド間操作が無効です


インタフェースにbuttonとlabelがあります.buttonをクリックすると、Labelの値を更新するためにスレッドが起動します.
  private void button1_Click(object sender, EventArgs e)
        {
            Thread thread1 = new Thread(new ParameterizedThreadStart(UpdateLabel));
            thread1.Start(" Label");
        }

        private void UpdateLabel(object str)
        {
            this.label1.Text = str.ToString();
        }

実行後、プログラムは「スレッド間操作が無効で、「label 1」を作成したスレッドからアクセスした」とエラーを報告します.
なぜならNETはスレッド間呼び出しコントロールを禁止しています.そうしないと、誰でもコントロールを操作でき、最後にエラーが発生する可能性があります.  
スレッド間呼び出しコントロールのいくつかの方法について説明します.

1つ目の方法:コンパイラがスレッド間アクセスをチェックすることを禁止する


これは最も簡単な方法で、スレッド間の衝突をチェックしないことに相当し、各スレッドが勝手にやることを許可し、最後にLable 1コントロールの値が何なのか予想しにくい(この方法は推奨されない)
   public Form1()
        {
            InitializeComponent();
            //  
            Control.CheckForIllegalCrossThreadCalls = false;
        }

第2の方法:delegateとinvokeを使用して他のスレッドからコントロールを呼び出す


コントロールのinvokeメソッドを呼び出すと、コントロールを制御できます.たとえば、
private void button2_Click(object sender, EventArgs e)
        {
            Thread thread1 = new Thread(new ParameterizedThreadStart(UpdateLabel2));
            thread1.Start(" Label");
        }

        private void UpdateLabel2(object str)
        {
            if (label2.InvokeRequired)
            {
                //  InvokeRequired , 
                Action<string> actionDelegate = (x) => { this.label2.Text = x.ToString(); };
                //  
                // Action<string> actionDelegate = delegate(string txt) { this.label2.Text = txt; };
                this.label2.Invoke(actionDelegate, str);
            }
            else
            {
                this.label2.Text = str.ToString();
            }
        }

第3の方法:delegateとBeginInvokeを使用して他のスレッドからコントロールを制御する


上のこれをlabel2.Invoke(actionDelegate, str); のInvokeをBeginInvokeメソッドに変更すればいいです
InvokeメソッドとBeginInvokeメソッドの違いは
Invokeメソッドは同期化されており、作業スレッドが完了するのを待っています.
BeginInvokeメソッドは非同期で、別のスレッドを作成して作業スレッドを完了します.

4つ目の方法:BackgroundWorkerコンポーネントの使用(この方法を推奨)


BackgroundWorkerはNETでは、プログラマが個別のスレッド上でいくつかの操作を実行できるようにするマルチスレッドタスクを実行するためのコントロールがあります.ダウンロードやデータベーストランザクションなど、時間のかかる操作.使い方が簡単だ
private void button4_Click(object sender, EventArgs e)
        {
            using (BackgroundWorker bw = new BackgroundWorker())
            {
                bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
                bw.DoWork += new DoWorkEventHandler(bw_DoWork);
                bw.RunWorkerAsync("Tank");
            }         
        }

        void bw_DoWork(object sender, DoWorkEventArgs e)
        {       
            ////  
            //
            Thread.Sleep(5000);
            e.Result = e.Argument + " ";
        }

        void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            // , , UI  
            this.label4.Text = e.Result.ToString(); 
        }