Splash Screen 加载窗体

  对于windows开 发人员来说在打开VS开发工具时,总是先呈现一个SplashScreen界面,登上几秒钟后才打开VS的主界面。这样的效果一般是在主界面需要加载大量 资源,为避免主界面变成“死”界面,而提供一个友好的Loading画面。为实现该效果,我们通常在加载主界面Application.Run(new MainForm())之前打开一个SplashScreen窗口,并在SplashScreen窗口中加载数据。

  微软提供了WindowsFormsApplicationBase类,该类提供了SplashScreen属性,及 OnCreateSplashScreen虚方法的接口。在实现自己的SplashScreen窗口时,主要重载 OnCreateSplashScreen方法,并创建一个Form对象,赋值给SplashScreen属性,并且该类还提供了 MinimumSplashScreenDisplayTime属性,用于设置SplashScreen窗口的呈现时间。当然你可以自己控制 SplashScreen窗口的呈现和关闭。

1. 实现Application类

首先我们需要实现WindowsFormsApplicationBase的基类SplashScreenApplication,并重新定义OnCreateSplashScreen方法。

WindowsFormsApplicationBase 类是位于Microsoft.VisualBasic.ApplicationServices命名空间下,需要添加 Microsoft.VisualBasic.dll引用。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.VisualBasic.ApplicationServices;

namespace Test_Splash_Screen
{
    internal sealed class SplashScreenApplication : WindowsFormsApplicationBase
    {
        public SplashScreenApplication()
        {
            base.IsSingleInstance = true;
            base.EnableVisualStyles = true;
            base.MinimumSplashScreenDisplayTime = 2000;
        }

        protected override void OnCreateMainForm()
        {
            this.MainForm=new Main_Form();
            //base.OnCreateMainForm();
        }

        protected override void OnCreateSplashScreen()
        {
            this.SplashScreen = new SplashScreenForm();
            //base.OnCreateSplashScreen();
        }
    }
}

其中Main_Form为主窗口,SplashScreenForm为Loading窗口,并设置2000毫秒SplashScreen自动关闭,并试图打开主窗体。

Application会首先执行OnCreateSplashScreen方法,然后执行OnCreateMainForm窗口。需要注意的是,2000毫秒并不是两个方法的执行的时间间隔,而是主窗体创建2000毫秒后才关闭SplashScreen窗体,并显示主窗体。这里的 SplashScreenForm不能用于加载数据,因为2000毫秒结束就会关闭,我们不能保证SplashScreen可以在2000毫秒吧数据加载完成。

2. 实现加载效果

这里SplashScreen的目的是加载数据,而不是简单的友好效果,因此简单的2000毫秒不能达到我们加载数据的需求。鉴于此,我们需要自己控制 SplashScreen界面,当数据加载完成后才能关闭SplashScreen窗口,并显示主界面。

为达到加载数据的效果,这里会在 SpashScreen界面显示加载数据的过程。代码如下:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

using System.Threading;
using Microsoft.VisualBasic.ApplicationServices;

namespace Test_Splash_Screen
{
    internal sealed class SplashScreenApplication2 : WindowsFormsApplicationBase
    {
       public ManualResetEvent resetEvent = new ManualResetEvent(true);

       public void SplashScreenApplication2()
        {
            base.IsSingleInstance = true;
            base.EnableVisualStyles = true;
        }

        protected override void OnCreateMainForm() {
            if (resetEvent.WaitOne()) {
                this.MainForm = new Main_Form();
            }
        }

        protected override void OnCreateSplashScreen() {
            this.SplashScreen = new SplashScreenForm();
        }
    }
}

为演示加载过程,SplashScreenForm还负责了加载数据:

public partial class SplashScreenForm : Form {
        static string[] Resources = new string[]{
            "Check update.",
            "Updating",
            "Downloading xxx.dll from remote server.",
            "Downloading xxx.config from remote server.",
            "Updated.",
            "Check if the devices pluged in.",
            "Open devices.",
            "Load data from database.",
            "Load file data from remote.",
            "Download necessary files.",
            "Ready"
        };

        public SplashScreenForm() {
            InitializeComponent();
            this.Opacity = 0.8;
            Program.app.resetEvent.Reset();
        }

        private void SplashScreenForm_Load(object sender, EventArgs e) {
            backgroundWorker1.RunWorkerAsync();
        }

        private delegate void run();

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
            float total = 0f;
            float pre = 100f / Resources.Length;

            foreach (string res in Resources) {
                total += pre;
                backgroundWorker1.ReportProgress((int)total, res);
                Thread.Sleep(1000);
            }
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) {
            this.Invoke(new run(() => {
                label1.Text = e.UserState.ToString();
                progressBar1.Value = e.ProgressPercentage;
            }));
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
            this.Invoke(new run(() => {
                label1.Text = "Inititalization finished.";
                progressBar1.Value = 100;

            }));

            Thread.Sleep(1000);

            this.Invoke(new run(() => {
                this.Close();
                Program.app.resetEvent.Set();
            }));
        }
    }

程序入口:

static class Program {
        public static SplashScreenApplication app = new SingleInstanceApplication();
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args) {
            app.Run(args);
        }
    }

运行效果
运行效果如下图:

其他
另外我们的加载数据过程只在SplashScreen窗口中,那么MainForm就不能加载太耗时的资源了,否则关闭SplashScreen窗口后,
才开始创建MainForm窗体,就其不到Loading的效果了。如果希望在MainForm中加载数据的,也可以修改代码,在MainForm中控制
SplashScreen的关闭。

参考文章

1. SplashScreen实现加载数据

时间: 07-21

Splash Screen 加载窗体的相关文章

[转] 从 dll 程序集中动态加载窗体

无涯 原文 从 dll 程序集中动态加载窗体 [原创] 昨天晚上花了一晚上时间写了一个从程序集中动态加载窗体的程序.将任何包含窗体的代码编译成 dll 文件,再把 dll 文件拷贝到本程序的目录下,本程序运行时即可动态检查到 dll 文件中的窗体,将窗体类的类型在程序菜单中显示出来,点击菜单即可运行对应的窗体. 本程序主要用到了 Assembly 类动态加载程序集,再得到程序集中包含类的 Type 类型,动态生成类实例,动态调用类方法.个人觉得这是一种提供高度松耦合,可随意扩展的程序结构框架,希

通过反射获取DLL的类实现加载窗体

1.创建一个DLL 类库,并新建一个窗体类,这个直接在vs上操作就好 2. 建立一个Testassembly工程 新建一个测试类 namespace Testassembly { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { string ss = AppDomain.Curren

pannel加载窗体

public static void loadFillForm(Panel panel, System.Windows.Forms.Form frm) { if (frm != null && panel != null) { frm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; frm.ShowIcon = false; frm.ShowInTaskbar = false; frm.TopLevel = fals

iOS欢迎界面Launch Screen动态加载广告

有许多应用程序在打开的时候,欢迎界面会加载一张连网获取的广告图片或者显示一组动画,这样的效果是如何做到的呢?下面给大家介绍一种简单的实现加载广告的方式. 程序运行起来,欢迎界面之后,会进入AppDelegate,因此我们可以在application: didFinishLaunchingWithOptions:添加代码完成想要的效果.连网获取图片可以用第三方SDWebImage实现,所以需要先将第三方文件夹导入.因为显示广告的页面是在欢迎界面基础上显示的,因此可以直接利用LaunchScreen

实现虚拟模式的动态数据加载Windows窗体DataGridView控件 .net 4.5 (一)

实现虚拟模式的即时数据加载Windows窗体DataGridView控件 .net 4.5 原文地址 :http://msdn.microsoft.com/en-us/library/ms171624.aspx  译 Q:77811970 实现虚拟模式的原因之一 DataGridView控制只检索数据,因为它是必要的. 这就是所谓的 即时数据加载 . 如果你正在与一个非常大的表在一个远程数据库,例如,您可能希望避免启动延迟,只检索所需的数据显示和检索额外的数据只有当用户新行滚动到视图. 如果客户

WPF加载Winform窗体时 报错:子控件不能为顶级窗体

一.wpf项目中引用WindowsFormsIntegration和System.Windows.Forms 二.Form1.Designer.cs 的 partial class Form1 设置为:public partial class Form1 三.代码如下: XXXX.Form1 Zhuwindow = new XXXX.Form1(); Zhuwindow.TopLevel = false; Zhuwindow.FormBorderStyle = System.Windows.Fo

DevExpress 使用 XtraTabbedMdiManager 控件以 Tab样式加载 Mdi窗体并合并 RibbonControl 解决方案

最近刚接触到 DevExpress 13.1 这个皮肤组件, 觉得相当好用 于是开始准备搭建 个小应用的主体框架. 找了好久的就是没找到对应的文章来讲解这一块.. 翻了他们主网站上人家问的,以及API 才摸索... 不懂英文好吃力呀~~~ 首先选到的就是,依旧用 Mdi子窗体模式加载子模块 第一步: 创建一个主 RibbonForm 为: ParentForm 1.1 设置 RibbonControl 属性 MdiMergeStyle 为: Always 第二步: 在左边拖入一个NavBarCo

如何在Dynamics CRM 2011 的窗体表单上加载报表

1.代码 function onloadReport() { if (crmForm.FormType != 1 && crmForm.FormType != 5) { $("#tab4Tab").click(function () { var test1 = document.getElementById("IFRAME_tgxfa"); if (test1.readyState == "complete") { var tes

Xamarin Android -创建Splash Screen (一)

......(空话少说) Xamarin 开发的技术资料很少,通过学习,把自己的学习过程及其中碰到的问题与大家分享. Splash Screen 就是在应用程序启动时,出现的一张图片,一般App的Splash Screen都是动态的广告信息. 先学习一下如何加载一个固定的Splash Screen. 一.在Resource/values/Styles.xml添加代码. <?xml version="1.0" encoding="UTF-8" ?> <