如果在BackgroundWorker运行过程中关闭窗体…

简介:

在Windows Form应用中,BackgroundWorker 类允许您在单独的专用线程上运行操作。耗时的操作(如下载和数据库事务)在长时间运行时可能会导致用户界面 (UI) 似乎处于停止响应状态。如果您需要能进行响应的用户界面,而且面临与这类操作相关的长时间延迟,则可以使用 BackgroundWorker 类方便地解决问题。由于操作是异步执行的,用户可能在异步操作执行过程中关闭当前窗体,而窗体的关闭会伴随着Dispose方法的执行。如果我们注册了BackgroundWorker的RunWorkerCompleted事件,并且在该事件处理程序中需要操作这个被Disposed的窗体,就会出现一些无法预知的异常。

一、一个简单的例子

我们写一个简单的例子来说明上述的场景:在一个非主窗体(主窗体的关闭会导致程序的终止)的Windows窗体中,一个BackgroundWorker被用于异步地执行一段耗时的操作。在我们的例子中,通过让线程休眠10秒来模拟这个“耗时操作”。方法backgroundWorker_RunWorkerCompleted是BackgroundWorker的RunWorkerCompleted事件处理方法,在这里我们通过MessageBox来显示当前窗体的IsDisposed属性值。注册到该BackgroundWorker的异步操作通过点击某个按钮开启。相关的代码如下所示。

   1: public partial class BgwForm : Form
   2: {
   3:     public BgwForm()
   4:     {
   5:         InitializeComponent();
   6:     }
   7:  
   8:     private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
   9:     {
  10:         Thread.Sleep(10000);
  11:     }
  12:  
  13:     private void btnStart_Click(object sender, EventArgs e)
  14:     {
  15:         this.backgroundWorker.RunWorkerAsync();
  16:     }
  17:  
  18:     private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  19:     {
  20:         MessageBox.Show(string.Format("Is the form disposed? {0}", this.IsDisposed));
  21:     }
  22: }

image 当该窗体被显示出来后,点击按钮让注册到该BackgroundWorker的异步操作开始执行,然后在操作结束之前(10秒)将当前窗体关闭。10秒钟之后,如右图所示的一个MessageBox会显示出来,表明在执行BackgroundWorker的RunWorkerCompleted事件处理程序的时候,承载它的窗体已经被Dispose。如果在你将一些针对窗体的操作注册到RunWorkerCompleted事件上,操作一个Disposed窗体,很难保证能否正常进行。而实际上,我们通常注册该事件在窗体上进行一些状态信息的显示,既然窗体都被关闭,这些操作就无需执行。那么,有什么方式可以确保在窗体关闭的状态下阻止RunWorkerCompleted事件处理程序的执行呢?

二、通过IsDisposed属性判断窗体的状态

我们最容易想到的肯定是在RunWorkerCompleted事件处理程序通过窗体的IsDisposed属性判断窗体的状态,并根据状态进行相应的操作。

   1: private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
   2: {
   3:     if (!this.IsDisposed)
   4:     { 
   5:         //Do Something
   6:     }
   7: }

三、在Closed事件中移除对RunWorkerCompleted事件的注册

我们还有另一种方案,那就是在关闭窗体的时候将对RunWorkerCompleted事件的注册接触掉,我们只需要将该操作注册到窗体的FormClosed事件中。

   1: private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
   2: {
   3:     //Do Something
   4: }
   5:  
   6: private void BgwForm_FormClosed(object sender, FormClosedEventArgs e)
   7: {
   8:     this.backgroundWorker.RunWorkerCompleted -= backgroundWorker_RunWorkerCompleted;
   9: }

作者:蒋金楠
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
Qt窗口关闭和应用程序停止是否调用析构函数的一些说明
Qt窗口关闭和应用程序停止是否调用析构函数的一些说明
Qt窗口关闭和应用程序停止是否调用析构函数的一些说明
|
C#
WinForm关闭主窗体后,仍然有后台进程运行。
WinForm关闭主窗体后,仍然有后台进程运行。
334 0
|
C# Windows
C# 程序关闭托盘图标不会自动消失
原文:C# 程序关闭托盘图标不会自动消失 c#程序关闭托盘图标不会自动消失,进程的托盘图标却不能随着进程的结束而自动消失  必须将鼠标移到图标上面时才能消失?  请问如何才能做到图标随着进程的结束而自动消失呢(外部强行结束,如在任务管理器将其结束), windows系统好多程序都会这样。
1206 0
|
安全 C#
WPF的消息机制(三)- WPF内部的5个窗口之处理激活和关闭的消息窗口以及系统资源通知窗口
原文:WPF的消息机制(三)- WPF内部的5个窗口之处理激活和关闭的消息窗口以及系统资源通知窗口 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.
1012 0
|
C# C++
获取当前进程(程序)主窗体句柄并设置wpf的父窗体为此句柄
原文:获取当前进程(程序)主窗体句柄并设置wpf的父窗体为此句柄 有时候在c++调用wpf控件的时候,wpf控件想自己显示窗体,但需要设置owner属性。迂回解决办法是设置wpf的window窗体的父窗体为进程的句柄。
3059 0
WebBrowser 的 DocumentCompleted事件不执行的解决方法
原文:WebBrowser 的 DocumentCompleted事件不执行的解决方法 WebBrowser 的 DocumentCompleted事件不执行的解决方法: 使用WebBrowser的ProgressChanged事件,在时间中判断((WebBrowser)sender).ReadyState == WebBrowserReadyState.Complete是否成立,若成立则执行DocumentCompleted的处理。
1483 0