使用ApplicationContext类来完全封装闪屏功能

http://www.codeproject.com/KB/cs/applicationcontextsplash.aspx
http://weblogs.asp.net/justin_rogers/archive/2004/04/11/111162.aspx
 
1. 简介
 
对于开发者,我们总是想要在我们的应用程序中加入一些很酷的功能。这是我们程序员血液中无法抑制的天性本能。要不然我们早就改行做审计或销售了。对于Winform应用程序,增加酷的功能的方法之一是在应用程序启动前增加闪屏功能。
 
2. Application Context(应用程序上下文):它到底干些啥?
 
我首先花点时间说一下概念性的东西。如果了解我们的继承类在背后干了些什么会对理解有很大帮助。如果你对这些不感兴趣请跳过这章。
 
每个WinForms应用程序都有一个ApplicationContext类的实例,你可能只是不知道而已。我们来看一个WinForms的标准的Main()函数:
static void Main()
{
    Application.Run(new Form1());
}
 
你肯定看到过这个。不过你知道这个函数也能写成如下的形式?:
static void Main()
{
    ApplicationContext appCtx = new ApplicationContext(new Form1());
    Application.Run(appCtx);
}
(我试过了,的确可以)
 
在前一个例子中,Application.Run函数只是创建了一个新的ApplicationContext实例,然后把Form对象传递给它的构造函数(constructor)。在后一个例子中,我们只是手动进行了这个步骤。所以从现在开始,请记住每个WinForm应用程序有一个ApplicationContext实例,它包含着Main Form的实例。ApplicationContext的目的就是作为你应用程序的Main Form和UI线程之间的应用程序启动与终结的标识链接(notification link )。UI线程是你的应用程序用户界面所在的主线程,它负责处理应用程序的消息循环。这个消息队列接收来自操作系统的事件消息,例如鼠标右键点击,空格键被按下了,并把这些消息发送给了需要处理这些消息的Form。
 
消息循环是在ThreadContext类之中。这是一个私有的子类,定义在Application类之内。关于ThreadContext的内部机理的介绍非常少,不过你可以使用Anikrino工具(我也不知道是啥,有兴趣的google吧)来深入研究。
 
让我们返回Main函数。当Main()调用了Application.Run,它接着就会调用ThreadContext.RunMessageLoop,传递到新创建的ApplicationContext实例,而这个ApplicationContext实例中包含了应用程序的Main Form实例。然后RunMessageLoop注册了ThreadContext的回叫函数OnAppThreadExit函数在ApplicationContext的ExitThread事件后触发。这就让消息循环能得知用户什么时候关闭了应用程序的Main Form。接着RunMessageLoop把Main Form的Visible属性设置为true,这样用户就能最终看到Main Form。最后RunMessageLoop的工作就是进入真实的消息循环,开始接收和处理来自操作系统的事件消息。
(好像有点乱,我来整理一下:
Main() call Application.Run
|
/
ThreadContext.RunMessageLoop
|
/
pass in ApplicationContext instance(contain main form)
|
/
ThreadContext.RunMessageLoop call ThreadContext.OnAppThreadExit
|
/
ThreadContext.RunMessageLoop set main form visible=true
|
/
ThreadContext.RunMessageLoop start actual message loop
 
ApplicationContext类只有一个属性:MainForm。在我们之前看过的Main函数范例中,我们传入ApplicationContext构造函数的Form实例设置(get set to)了MainForm属性。set_MainForm属性会注册ApplicationContext.OnMainFormDestroy回叫函数在HandleDestroyed事件(用户关闭Form)后触发。那样ApplicationContext就知道应用程序main form什么时候被销毁。
 
这个回叫对于Windows应用程序非常重要。Forms不是应用程序,他们只是Application对象保持引用的对象。如果Application对象不知道什么时候main form被销毁,那么它会永无止境地运行消息循环。因此当用户关闭了main form,form会发起它自己的HandleDestroyed事件,而这个事件会调用ApplicationContext的OnMainFormDestroy回叫函数。这个回叫函数接着发起ThreadContext的ExitThread事件,调用ThreadContext的OnAppThreadExit回叫函数。而调用这个函数告诉ThreadContext应用程序的main form已经被销毁,它可以终结UI线程了。最后把应用程序的关闭消息返回给操作系统,清空所有资源,终结UI线程。(过程真纠结。。。。)
 
3. 根据上面的概念来创建一个闪屏
 
上面有些说得太多了,不过这有助于你来理解接下来我们究竟要做些什么。
 
微软本可以不暴露出ApplicationContext类来给我们使用,但他们最终还是暴露了出来。因此我们能继承然后自定义这个启动过程。本文中我们就会创造一个自定义的ApplicationContext,包括两个Form,一个闪屏Form,一个main form。
  

另外新建一个Class SplashAppContext.cs,这个SplashAppContext类继承ApplicationContext类。
ApplicationContext有两个构造函数ApplicationContext()与ApplicationContext(Form),后者在初始一个新的ApplicationContext实例的同时还会附带一个指定的Form。如果使用了这个构造函数,可能需要重载OnMainFormClosed函数,不然线程的消息循环会在MainForm关闭时随之关闭。

代码如下:

 

     class  SplashAppContext:ApplicationContext
    {
        Form mainForm 
=   null ;
        Timer splashTimer 
=   new  Timer();

        
public  SplashAppContext(Form mainForm, Form splashForm)
            : 
base (splashForm)
        {
            
this .mainForm  =  mainForm;
            splashTimer.Tick 
+=   new  EventHandler(splashTimer_Tick);
            splashTimer.Interval 
=   10000 ;
            splashTimer.Enabled 
=   true ;
        }

        
void  splashTimer_Tick( object  sender, EventArgs e)
        {
            splashTimer.Enabled 
=   false ;
            splashTimer.Dispose();

            
base .MainForm.Close();
        }

        
protected   override   void  OnMainFormClosed( object  sender, EventArgs e)
        {
            
if  (sender  is  Splash)
            {
                
base .MainForm  =   this .mainForm;
                
base .MainForm.Show();
            }
            
else   if  (sender  is  Main) 
            {
                
base .OnMainFormClosed(sender, e);
            }
        }
    }

 

之前提到过的Timer的知识就是应用在这个上面的,回忆不起来用法的可以参考http://www.cnblogs.com/galaxyyao/archive/2009/10/04/1577860.html。关于
public SplashAppContext(Form mainForm, Form splashForm)
            : base(splashForm)
这段,感谢renyu同学的解释。它会先运行父类的方法再运行子类的方法。因为是base(splashForm),所以会先创建一个splashForm,开启计时器splashTimer,然后创建一个mainForm。
少女计时中。。。(这是一个neta,请54)
当计时器到点,触发base.MainForm.Close(),但由于OnMainFormClosed被重载过,所以在关闭时还会检查一下是不是splashForm。如果是splashForm的话,换最终要显示的mainForm显示,然后splashForm自己dispose销毁。
最后我们打开包含Main函数的Program.cs,把Application.Run(new Main());替换成自定义的ApplicationContext:

 

SplashAppContext splashContext  =   new  SplashAppContext( new  Main(),  new  Splash());
Application.Run(splashContext);

 

这样,一个简单的闪屏程序就完成了。


转载于:https://www.cnblogs.com/galaxyyao/archive/2009/10/28/1591632.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值