.NET跨线程控件的相关操作

在.NET中,如果我们在非UI线程上访问窗体上的控件的时候,会产生一个跨线程调用的异常,那么如何处理这种情况呢?在上一章中,我介绍了使用Control.Invoke方法,如果你不习惯使用委托,那么.Net还为我们提供了一个组件BackgroundWorker,你可以使用这个组件,以事件的方式去处理这种跨线程的控件访问。下面我就来详细的介绍一下这个组件的用法。

创新互联公司自2013年起,公司以成都网站设计、做网站、系统开发、网络推广、文化传媒、企业宣传、平面广告设计等为主要业务,适用行业近百种。服务企业客户成百上千,涉及国内多个省份客户。拥有多年网站建设开发经验。为企业提供专业的网站建设、创意设计、宣传推广等服务。 通过专业的设计、独特的风格,为不同客户提供各种风格的特色服务。

我们先来看一下BackgroundWorker提供了哪些常用的成员,

事件

◆DoWork:我们在这个事件中,执行需要异步处理的工作。

◆ProgressChanged:我们在这个事件中,接收并处理异步处理过程中的信息。

◆RunWorkerCompleted:我们在这个事件中,执行异步处理结束的工作。

方法

◆RunWorkerAsync()和RunWorkerAsync(object argument):这两个方法触发DoWork事件,开始异步操作。

◆ReportProgress(int percentProgress)和ReportProgress(int percentProgress, object userState):这两个方法触发ProgressChanged事件。

◆CancelAsync:结束后台的异步操作。

属性

◆bool CancellationPending:指示当前的后台的异步操作是否正在被取消,执行CancelAsync方法会导致这个属性为true。

◆bool IsBusy:指示当前的后台异步操作是否正在进行,进行中为true。

◆bool WorkerReportsProgress:获取或设置当前的BackgroundWorker是否可以执行ProgressChanged方法。

◆bool WorkerSupportsCancellation:获取或设置当前的BackgroundWorker是否可以执行CancelAsync方法。

OK,有了上面这些成员,我们来看一下BackgroundWorker是如何工作的。

Step 1. 当然是定义一个BackgroundWorker的实例,你可以从工具箱中拖拽一个BackgroundWorker控件到窗体上或者在代码中直接声明;

Step 2. 生成DoWork事件并在DoWork事件的中添加需要异步执行的代码。在异步执行的代码中,如果需要处理界面中的控件,请调用ReportProgress方法,而不要直接处理(例如给控件赋值),因为DoWork事件跟正常的界面的事件不同,这个事件在非UI线程上执行,所以才能异步执行。

Step 3. 生成ProgressChanged事件并添加控件处理的代码,因为这个事件是在UI线程上执行的,所以可以给界面中的控件进行赋值等操作。

Step 4. 如果需要,请生成RunWorkerCompleted事件,在此处理异步执行结束的业务逻辑。当然,此事件也是在UI线程上执行的,可以给界面中的控件进行赋值等操作。

Step 5. 在需要执行异步操作的地方调用RunWorkerAsync方法,开始执行异步调用。

下面是具体的代码:

 
 
 
  1. public Form1()     
  2.  {     
  3.    InitializeComponent();    
  4.      bWorker.DoWork += new DoWorkEventHandler(bWorker_DoWork);    
  5.      bWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bWorker_RunWorkerCompleted);   
  6.      bWorker.ProgressChanged += new ProgressChangedEventHandler(bWorker_ProgressChanged);     
  7.    this.Text = "UI thread id is:" + Thread.CurrentThread.ManagedThreadId.ToString();     
  8.  }     
  9. BackgroundWorker bWorker = new BackgroundWorker();    
  10. void bWorker_DoWork(object sender, DoWorkEventArgs e)    
  11.  {    
  12.  int tick = (int)e.Argument;    
  13.   Thread thr = Thread.CurrentThread;    
  14.  for (int i = 0; i < 30; i++)    
  15.   {    
  16.     if (bWorker.CancellationPending)    
  17.      {    
  18.         e.Cancel = true;    
  19.           //break;    
  20.    }    
  21.  else    
  22.     {    
  23.            Thread.Sleep(TimeSpan.FromSeconds(tick));    
  24.           bWorker.ReportProgress(i, DateTime.Now.ToString() + "\\TID:" + thr.ManagedThreadId.ToString());    
  25.       }    
  26.     }    
  27.        
  28.  }   
  29. void bWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)    
  30.  {    
  31. progressBar1.Value = e.ProgressPercentage;  
  32.      label1.Text = e.UserState.ToString();   
  33.  }    
  34. void bWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)  
  35.  {    
  36.  label1.Text = DateTime.Now.ToString();   
  37.      progressBar1.Value = progressBar1.Maximum;    
  38.      if (e.Cancelled)    
  39.  label1.Text = "User cancelled.";    
  40. }    
  41. private void btnInvoke_Click(object sender, EventArgs e)   
  42. {   
  43.   bWorker.WorkerReportsProgress = true;   
  44.     bWorker.WorkerSupportsCancellation = true;    
  45.     if (!bWorker.IsBusy)   
  46.      bWorker.RunWorkerAsync(1);    
  47. }   
  48. private void btnCancel_Click(object sender, EventArgs e)    
  49.  {    
  50.     if (bWorker.WorkerSupportsCancellation)   
  51.         bWorker.CancelAsync();    

上面的代码请注意几个地方:

1. 第50行,开始调用RunWorkerAsync方法前,请先判断IsBusy属性是否是false,因为如果为true,则说明上一次的调用还没有结束,再次调用会引发异常。

2. 第56行,调用CancelAsync方法前,请先设置WorkerSupportsCancellation属性为true,否则会引发异常。

3. 第26行,调用ReportProgress方法前,请先设置WorkerReportsProgress属性为true,否则会引发异常。

4. RunWorkerAsync方法传递的参数是object类型,这个参数的值可以在DoWork事件的参数e中的属性Argument获得。

5. ReportProgress方法传递的参数可以在事件ProgressChanged中的参数e中获得。

6. 调用CancelAsync方法只是向后台的异步线程发出结束申请,具体什么时候结束,由线程自动管理。

7. 在RunWorkerCompleted事件中,如果想知道后台任务是正常执行完毕还是被调用CancelAsync方法强制中断,请参考事件的参数e的Cancelled属性。(奇怪的是这个属性不会在你调用CancelAsync方法后自动设置为true,你需要象代码中的20行那样进行设置。)

8. 请注意第7行和第26行的代码,这两段代码中的线程的ID,说明了DoWork事件和UI是在两个不同的线程上执行。

实际上BackgroundWorker并非直接用来解决跨线程的控件调用的问题,只是它提供了一种工作机制,可以让你的程序利用它来执行异步调用,并且在异步调用的过程中进行控件的操作。

好了,关于如何对界面中的控件进行跨线程的调用就介绍这么多吧,希望对大家有所帮助。

网站名称:.NET跨线程控件的相关操作
当前地址:http://www.shufengxianlan.com/qtweb/news36/148336.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联