关于如何使用自定义的结束消息循环的方式 (转载)
其实这个问题对于高手来说可能是很简单的,因为真正的实现过程并不复杂,实际上涉及到的代码也并不多,但是在没有搞清楚在.net下系统如何退出线程之前,这个问题还是困扰了我这个菜鸟很久的。
感觉上对于一个简单的单线程的winform程序来说,好像点击了主Form的close,主线程就自动退出了。但是它是如何退出的呢?
在查阅了MSDN和SDK之后,这个问题逐步的明朗了。
首先一定要清楚一件事,那就是当主窗体初始化完成后当前线程在做什么,其实是在等待(等待处理新的消息):
这一点还是很好理解的,可是如何定义退出呢?谁来负责消息循环的退出(即结束当前线程)呢?其实,Application.Run()这个方法是和另外一个类的实例配合使用的---ApplicationContext类。SDK中对这个类的解释是:指定有关应用程序线程的上下文信息。乍一听,很是迷惑。可是看过SDK提供的例子思路就清晰了很多。我对代码进行了精简,只留下了足以说明问题的部分。
我们通过上面的代码可以看到,实际上Run()方法是有参数的,也就是所谓的线程的上下文,它的参数就是ApplicationContext类或者它的派生类。通常情况下,如果我们没有自定义ApplicationContext的派生类的话,那么默认的线程上下文就是.net提供的ApplicationContext类本身。这时候,消息循环是通过主Form的OnClosed事件来结束的(果不出我之所料,不过好像太简单了,地球人都知道... ...)。需要特别说明的一点是,其实ApplicationContext只是负责监听(监听OnClosed事件),真正负责退出消息循环的还是Application类自己。
但是在上面的代码中我们通过构建自己的ApplicationContext类的实例(我习惯把class A的派生类叫做"自己的A类",大家明白即可),我们在类的内部重新定义了如何推出消息循环(其实就是按自己的需要重新定义退出消息循环的条件),可以看到,消息循环的退出不再是由于发生了主Fomr的OnClosed事件,而是子窗体的OnClosed事件(这里给出的条件似乎不是很典型,我们当然也可以响应其他的系统事件,来结束当前线程中的消息循环)。
这样一来,我们就可以实现自定义当前线程的消息循环的退出条件了。我感觉这样做在某些时候应该还是很有意义的,比如对于一个应用程序,它的主窗体并没有实际的意义,真正有意义的是所有的子窗体,换句话说当所有的子窗体都close掉以后,应用程序结束。这个时候主Form的close对于我们是没有意义的,我们可以在用户点击了主Form的close之后,通过CancelEventArgs 的实例e来取消主程序的结束,并隐藏主窗体,以防止用户对主窗体进行不必要的操作。
当然了,对于主窗体来说如果在某些时候还需要使用的话,干脆做成系统托盘会更好一些。
这时候,我们只需要在我们从ApplicationContext类派生出来的类中定义消息推出的条件就可以了,比如条件是子窗体的计数器为零则程序退出。(可一定要保证在程序启动的时候至少有一个子窗体呦)
最后不要忘了在程序中将派生类进行实例化,并且将实例对象作为Run()方法的参数。
感觉上对于一个简单的单线程的winform程序来说,好像点击了主Form的close,主线程就自动退出了。但是它是如何退出的呢?
在查阅了MSDN和SDK之后,这个问题逐步的明朗了。
首先一定要清楚一件事,那就是当主窗体初始化完成后当前线程在做什么,其实是在等待(等待处理新的消息):
这一点还是很好理解的,可是如何定义退出呢?谁来负责消息循环的退出(即结束当前线程)呢?其实,Application.Run()这个方法是和另外一个类的实例配合使用的---ApplicationContext类。SDK中对这个类的解释是:指定有关应用程序线程的上下文信息。乍一听,很是迷惑。可是看过SDK提供的例子思路就清晰了很多。我对代码进行了精简,只留下了足以说明问题的部分。
我们通过上面的代码可以看到,实际上Run()方法是有参数的,也就是所谓的线程的上下文,它的参数就是ApplicationContext类或者它的派生类。通常情况下,如果我们没有自定义ApplicationContext的派生类的话,那么默认的线程上下文就是.net提供的ApplicationContext类本身。这时候,消息循环是通过主Form的OnClosed事件来结束的(果不出我之所料,不过好像太简单了,地球人都知道... ...)。需要特别说明的一点是,其实ApplicationContext只是负责监听(监听OnClosed事件),真正负责退出消息循环的还是Application类自己。
但是在上面的代码中我们通过构建自己的ApplicationContext类的实例(我习惯把class A的派生类叫做"自己的A类",大家明白即可),我们在类的内部重新定义了如何推出消息循环(其实就是按自己的需要重新定义退出消息循环的条件),可以看到,消息循环的退出不再是由于发生了主Fomr的OnClosed事件,而是子窗体的OnClosed事件(这里给出的条件似乎不是很典型,我们当然也可以响应其他的系统事件,来结束当前线程中的消息循环)。
这样一来,我们就可以实现自定义当前线程的消息循环的退出条件了。我感觉这样做在某些时候应该还是很有意义的,比如对于一个应用程序,它的主窗体并没有实际的意义,真正有意义的是所有的子窗体,换句话说当所有的子窗体都close掉以后,应用程序结束。这个时候主Form的close对于我们是没有意义的,我们可以在用户点击了主Form的close之后,通过CancelEventArgs 的实例e来取消主程序的结束,并隐藏主窗体,以防止用户对主窗体进行不必要的操作。
当然了,对于主窗体来说如果在某些时候还需要使用的话,干脆做成系统托盘会更好一些。
这时候,我们只需要在我们从ApplicationContext类派生出来的类中定义消息推出的条件就可以了,比如条件是子窗体的计数器为零则程序退出。(可一定要保证在程序启动的时候至少有一个子窗体呦)
最后不要忘了在程序中将派生类进行实例化,并且将实例对象作为Run()方法的参数。