Application.DoEvents()和多线程

首先将以下代码放到Button事件里面:

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

你会发现当点击Start按钮后,循环会一直进行,此时窗体会出现假死的状态,如:无法拖动。直到循环结束,textBox1中才会显示出结果。如何解决窗体的假死状态??

修改以上代码如下:

private void btnStart_Click(object sender, EventArgs e)
  {
      for (int q = 0; q < 100000; q++)
      {
          textBox1.Text = q.ToString();
          //实时响应文本框中的值
          Application.DoEvents();
      }
  }

此时再次点击Start按钮后,textBox中的数字会不断改变,同时,你也可以拖动窗体。。。

但是这样使用Application.DoEvents()好吗?如果用多线程来实现相同的效果呢?

多线程实现代码如下: 

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++)
      {

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

注意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。

posted on 2015-08-14 16:54  喝咖啡就蒜瓣儿  阅读(803)  评论(1编辑  收藏  举报

导航