views:

156

answers:

4

The concept of a splash screen doesn't strike me as something that should be so complicated, but I'm having trouble getting the whole splash screen painted.

Let's say I have two System.Windows.Forms.Forms: RealForm and SplashScreen. The RealForm contains the initial GUI. During the RealForm's loading process (that is, in the event handler for the Load event), RealForm creates a connection to a database and then tests the connection. This can take several seconds, so before I do all of this, I try to throw up a splash screen like so:

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

The problem is that the splash screen only gets partially drawn and so it doesn't really look like much of a splash screen. Any idea why? What should I do?

For bonus points, does anyone know where to find an explanation for all series of events that occur in typical creation, usage, and destruction of forms? The above problem is probably because I don't understand what order things occur or where to hook into form events.


UPDATE Close, but not quite: looking for a little more advice. Here's the current code:

    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();
    }

Unfortunately, the this.Visible = false doesn't do anything, because it is automatically set to true in code that I don't control. So, to get around this, I put the this.Visible = false into the handler for the form's Shown event. However, as you can probably guess, you can still see the form for a split second... so this is not really a good solution.

Is there any way to wait on the worker thread while I'm still in the Load handler?

+1  A: 

Try putting the call to loadAndCheckDatabase in a background thread, moving the close of the splash screen there, or simply closing it with a timer in the splash screen. With the work in a background thread, the all UI functions will be able to operate without interruption.

Russ
+6  A: 

You are displaying the splash screen and checking your database on the same thread. The thread can only do one thing at a time.

A quick and cheap way to fix this is to have loadAndCheckDatabase() call Application.DoEvents() periodically. However that's a cheap fix.

You really want to run loadAndCheckDatabase() on its own thread, a BackgroundWorker is a nice simple way to do this.

Matt Greer
This might be obvious but make sure you don't have any UI code in your loadAndCheckDatabase call, not even a message box or you could run into trouble.
Steve Sheldon
I wouldn't even bother with Application.DoEvents(), just use BackgroundWorker. If you want to execute a simple unit of logic whilst the UI remains responsive, use BackgroundWorker. If you want the UI thread to go and execute everything thats waiting on the UI's message queue, *even* if the user's managed to queue up mouse clicks that perform random other bits of logic which interfere with your current operation in a way that looks like loads of threads are running, but actually only one is, then use Application.DoEvents().
Alex Humphrey
A: 

You should be running the splash screen in a different thread, that should allow it to draw properly.

Have a look here:

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

Daniel Frear
Since the splash screen is a UI component, it really should run on the UI thread (the main thread of a WinForms app). The loadAndCheckDatabase() should be pushed off to a worker thread.
Matt Greer
UI components really can't and shouldn't run on a background thread--they should only run on the main thread.
Russ
Right, no UI on a background thread, you will get a bunch of cross thread call exceptions.
Steve Sheldon
I thought this looked promising. Can you help me understand why this is a bad thing? It seems easier, and since the SplashScreen doesn't really *do* anything I don't see why it can't go in a different thread.
John Berryman
You might be able to get away with it in this case, but in general it's a bad idea. I really do recommend learning `BackgroundWorker`. It might seem confusing at first, but it's actually really easy to use. It's a very powerful tool to have in your WinForms arsenal.
Matt Greer
@Matt... learning
John Berryman
@Matt cheers, I "did" know that but apparently I conveniently forgot when it mattered!
Daniel Frear
A: 

I once blogged about creating a splash screen. See if it helps you out:

http://crazorsharp.blogspot.com/2009/06/creating-splash-screen-in-net-with.html

BFree