Application.DoEvents()和多線程

首先將如下代碼放到Button事件裏面:多線程

private void btnStart_Click(object sender, EventArgs e)
  {
      for (int q = 0; q < 100000; q++)
      {
          textBox1.Text = q.ToString();
      }
  }this

你會發現當點擊Start按鈕後,循環會一直進行,此時窗體會出現假死的狀態,如:沒法拖動。直到循環結束,textBox1中才會顯示出結果。如何解決窗體的假死狀態??spa

修改以上代碼以下:線程

private void btnStart_Click(object sender, EventArgs e)
  {
      for (int q = 0; q < 100000; q++)
      {
          textBox1.Text = q.ToString();
          //實時響應文本框中的值
          Application.DoEvents();
      }
  }orm

此時再次點擊Start按鈕後,textBox中的數字會不斷改變,同時,你也能夠拖動窗體。。。blog

可是這樣使用Application.DoEvents()好嗎?若是用多線程來實現相同的效果呢?事件

多線程實現代碼以下: it

public Form1()
  {
      InitializeComponent();
      //不捕獲跨線程調用引發的異常
      CheckForIllegalCrossThreadCalls = false;
  }
  private void btnStart_Click(object sender, EventArgs e)
  {
          Thread s1 = new Thread(new ThreadStart(ThreadMeth));
          s1.Start();
  }
  public void ThreadMeth()
  {
      for (int q = 0; q < 100000; q++)
      {io

          textBox1.Text = q.ToString();
      }
  }object

注意Form1()裏面添加了一行代碼,解決跨線程調用產生的異常。

以上代碼和使用Application.DoEvents()達到相同的效果。

下面咱們來比較一下,使用Application.DoEvents()和使用多線程哪一個更耗時?

代碼以下:
  public void ThreadMeth()
  {
      label1.Text = DateTime.Now.ToString();
      for (int q = 0; q < 100000; q++)
      {
          textBox1.Text = q.ToString();
      }
      label5.Text = DateTime.Now.ToString();

  }

  private void btnStartDo_Click(object sender, EventArgs e)
  {
      label3.Text = DateTime.Now.ToString();
      for (int q = 0; q < 100000; q++)
      {
          textBox2.Text = q.ToString();
          Application.DoEvents();//實時響應文本框中的值
      }
      label6.Text = DateTime.Now.ToString();

  }

(假設以上比較時間的代碼處在正確的位置)由此可知,Application.DoEvents()消耗的時間更少,但這裏並不建議使用Application.DoEvents(),由於它會引發不少未知的錯誤。

 

補充:因爲顯示的定義 CheckForIllegalCrossThreadCalls = false;並非好的方法,下面來改進一下,以下:

 int i;

  private void btnStart_Click(object sender, EventArgs e)

  { 

       Thread s1 = new Thread(new ThreadStart(ThreadMeth)); 

       s1.Start();

  }

  private void ThreadMeth() 

  {

       for ( i = 0; i < 100000; i++)

       {

           MethodInvoker mi = new MethodInvoker(Count);

           this.Invoke(mi);

           //BeginInvoke(mi);

        }

  }

  private void Count() 

  {

       textBox1.Text = i.ToString();

  } 

MethodInvoker實質上是一個委託,查看其定義可知...

using System;                                                                                           

namespace System.Windows.Forms 

{

    // 表示一個委託,該委託可執行託管代碼中聲明爲 void 且不接受任何參數的任何方法。

    public delegate void MethodInvoker();

以上用匿名委託的方式彷佛更簡潔,代碼以下:

private void btnStart_Click(object sender, EventArgs e)                 

{

     new Thread((ThreadStart)(delegate()

     {

           for (int i = 0; i < 10000; i++)

           {

                label1.Invoke((MethodInvoker)delegate()

                {

                      textBox1.Text = i.ToString();

                 });

            };

      })) .Start();                 

在次線程上計算,在主線程上調用label。

相關文章
相關標籤/搜索