zoukankan      html  css  js  c++  java
  • 使用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);

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


  • 相关阅读:
    魔兽争霸3 冰封王座 w3g文件如何打开
    魔兽争霸3怎么玩
    笔记本电脑 联想 Thinkpad E420 无法打开摄像头怎么办
    笔记本能连上WIFI网络,但是无法上网怎么办
    佳能打印机 打不出黑色怎么办
    佳能打印机 出现5100错误怎么办
    UG如何把语言改成中文,UG如何把界面语言改成中文
    [Spring] Spring Data JPA
    基于控制权限和登录验证跳转的django登录界面的实现
    windows环境下nutch2.x 在eclipse中实现抓取数据存进mysql详细步骤
  • 原文地址:https://www.cnblogs.com/galaxyyao/p/1591632.html
Copyright © 2011-2022 走看看