制作闪屏

时间:2010-08-13 16:15:34

标签: c# winforms splash-screen

启动画面的概念并没有让我觉得应该是如此复杂,但是我在绘制整个启动画面时遇到了麻烦。

假设我有两个System.Windows.Forms.Form:RealForm和SplashScreen。 RealForm包含初始GUI。在RealForm的加载过程中(即,在Load事件的事件处理程序中),RealForm创建与数据库的连接,然后测试连接。这可能需要几秒钟,所以在我做所有这些之前,我会试着像这样抛出一个闪屏:

private void RealForm_Load(object sender, EventArgs e)
{
    SplashScreen splash = new SplashScreen();
    splash.Show();
    loadAndCheckDatabase();
    splash.Close();
}

问题是启动画面只能被部分绘制,因此它看起来并不像闪屏。知道为什么吗?我该怎么办?

对于奖励积分,有没有人知道在哪里可以找到在表格的典型创建,使用和销毁中发生的所有系列事件的解释?上面的问题可能是因为我不明白事情发生的顺序或者在哪里挂钩表单事件。


更新 关闭,但不完全:寻求更多建议。这是当前的代码:

private SplashScreen splash = new SplashScreen();

private void RealForm_Load(object sender, EventArgs e)
{

    splash.Show();

    BackgroundWorker worker = new BackgroundWorker();
    worker.DoWork += new DoWorkEventHandler(worker_DoWork);
    worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler
         (worker_RunWorkerCompleted);
    worker.RunWorkerAsync();
    this.Visible = false;

}

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    splash.Close();
    this.Visible = true;
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    loadAndCheckDatabase();
}

不幸的是,this.Visible = false没有做任何事情,因为它在我无法控制的代码中自动设置为true。因此,为了解决这个问题,我将this.Visible = false放入了表单Shown事件的处理程序中。但是,正如你可能猜到的那样,你仍然可以看到表格一瞬间......所以这不是一个很好的解决方案。

当我还在Load处理程序中时,有没有办法等待工作线程?

6 个答案:

答案 0 :(得分:9)

您正在显示启动画面并在同一个线程上检查数据库。线程一次只能做一件事。

解决此问题的一种快速而便宜的方法是定期loadAndCheckDatabase()调用Application.DoEvents()。然而,这是一个廉价的解决方案。

你真的想在自己的线程上运行loadAndCheckDatabase(),BackgroundWorker是一个很好的简单方法。

答案 1 :(得分:2)

像我一样,你可能会把它想象成一个事后的想法,并且不想经历重新设计你的代码以适应多线程架构......

首先创建一个名为SpashScreen的新表单,在属性中单击BackgroundImage并导入所需的任何图像。同时将FormBorderStyle设置为None,这样就无法单击x来关闭屏幕。

    public Form1()
    {
        InitializeComponent();

        BackgroundWorker bw = new BackgroundWorker();
        bw.WorkerSupportsCancellation = true;
        bw.DoWork += new DoWorkEventHandler(bw_DoWork);
        bw.RunWorkerAsync();  // start up your spashscreen thread
        startMainForm();      // do all your time consuming stuff here  
        bw.CancelAsync();     // close your splashscreen thread  
    }


    private void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;

        SplashScreen ss = new SplashScreen();
        ss.Show();

        while (!worker.CancellationPending) //just hangout and wait
        {
            Thread.Sleep(1000);
        }

        if (worker.CancellationPending)
        {
            ss.Close();
            e.Cancel = true;
        }

    }

这不支持进度条或任何花哨的东西,但我相信它可以调整。

答案 2 :(得分:1)

尝试在后台线程中调用loadAndCheckDatabase,在那里移动启动画面的关闭,或者只是在启动画面中使用计时器关闭它。通过后台线程中的工作,所有UI功能将能够不间断地运行。

答案 3 :(得分:1)

您应该在不同的线程中运行启动画面,以便正确绘制。

看看这里:

http://www.codeproject.com/KB/cs/prettygoodsplashscreen.aspx

答案 4 :(得分:1)

为什么不在运行应用程序时打开一个表单,加载你需要加载到类中的任何内容,然后在加载完成后,打开主表单并将类发送到其中?或者,您可以使用单例来加载所有内容。

在您的Program.cs中:

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new SplashScreen());
    }

然后在SplashScreen中:

    public SplashScreen()
    {
        InitializeComponent();
        LoadEverything();
        this.Visible = false;
        MainForm mainForm = new MainForm(LoadedClass);
        mainForm.ShowDialog();
        this.Close();
    }

我需要更新此内容:

这是工作代码(以上只是概念)。

    public SplashScreen()
    {
        InitializeComponent();
        _currentDispatcher = Dispatcher.CurrentDispatcher;

        // This is just for the example - start a background method here to call
        // the LoadMainForm rather than the timer elapsed
        System.Timers.Timer loadTimer = new System.Timers.Timer(2000);
        loadTimer.Elapsed += LoadTimerElapsed;
        loadTimer.Start();
    }

    public void LoadMainForm()
    {
        // Do your loading here
        MainForm mainForm = new MainForm();

        Visible = false;
        mainForm.ShowDialog();
        System.Timers.Timer closeTimer = new System.Timers.Timer(200);
        closeTimer.Elapsed += CloseTimerElapsed;

        closeTimer.Start();
    }

    private Dispatcher _currentDispatcher;

    private void CloseTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        if (sender is System.Timers.Timer && sender != null)
        {
            (sender as System.Timers.Timer).Stop();
            (sender as System.Timers.Timer).Dispose();
        }
        _currentDispatcher.BeginInvoke(new Action(() => Close()));
    }

    private void LoadTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        if (sender is System.Timers.Timer && sender != null)
        {
            (sender as System.Timers.Timer).Stop();
            (sender as System.Timers.Timer).Dispose();
        }
        _currentDispatcher.BeginInvoke(new Action(() => LoadMainForm()));
    }

答案 5 :(得分:-2)

您可以在.Net Framework 4.5中使用await命令 在任务完成之前,您的表单将不可见

    private void YourForm_Load(object sender, EventArgs e)
    {
        //call SplashScreen form
        SplashScreen splash = new SplashScreen();
        splash.Show();
        Application.DoEvents();
        //Run your long task while splash screen is displayed i.e. loadAndCheckDatabase
        Task processLongTask = loadAndCheckDatabase();
        //wait for the task to be completed
        processLongTask.Wait();
        splash.Close();

        //...
    }