Stupid VS2005/ .NET 2.0 splash screen restrictions. Is there a solution.

K

Kevin

I have just moved from 1.1, where I had my splash screen to a tee, to
2.0 where I find it impossible to get a satisfactory solution and its
driving me mad!

This is how a splash screen SHOULD work (and did in 1.1) when you load
a program (MICROSOFT, please take note!!!):
Splash screen appears
Login screen appears, user enters credentials.
If the login was successful the login box disappears, and the main form
starts loading. Whilst it is loading (which can take a few seconds) it
spits out messages to the splash screen (e.g. "retrieving accounts",
"populating listboxes" etc etc)
once the Main form has finished initialising it should appear BEHIND
the splash screen.
The splash screen should then disappear.

The whole time the splash screen should remain responsive with no
unpainted areas etc. It is also useful to show a "please wait..." with
an increasing/decreasing number of full stops or a progress bar to show
the user that the program is doing things.
In 1.1 I achieved this by creating the splash screen on a different
thread to the main one and then calling delegates to update the message
etc.

Unfortunately in .NET 2.0 this has changed. With the built in methods
for showing the splash screen, it basically shows the splash screen for
a predetermined amount of time and then it disappears and then creates
the main form. Only then can you initialise the main form, at which
point the user is confronted with a blank screen whilst the
initialisation occurs. No good.

With my old 1.1 way in 2.0, the program complains about crossthread
exceptions all the time because the splash screen is created on a
different thread. Turning them off (with
control.checkforillegalcrossthreadenabled = false)causes random
crashes, and isnt an ideal solution anyway.

So how can I do it? I need the splash screen to be responsive to
painting the whole time. I have tried putting a thread on it which
updates it every 250 milliseconds, and then calls Application.DoEvents.
This works fine as long as nothing else is happening, but as soon as I
initialise my main form these stop as they get held up in the message
queue.

This example does a lot of what I am after:
http://www.codeproject.com/useritems/CustomSplashScreen.asp

However, it does not allow the ability to add a login screen as there
is no message pump.

Please can someone help me as I am going mad here. Its such a simple
thing I am trying to do and yet it seems so hard!!!!
Thanks
Kevin
 
S

Stephany Young

So your prime gripe appears to be that MS arbitrarily fixed some 'bugs' that
allowed you to make illegal cross-thread calls in Framework 1.1? If that is
not what you mean then that is certainly how your post reads.

If you want to use your 'splash screen' and an 'early dialog' (login) before
your 'main form' is shown then simply make it so.

Uncheck the project setting that precludes you from doing this and put your
own code in place.

Your code from VB.NET 2003 will work with few modifications except that you
MUST craft your delegates and delegate handlers to avoid cross-thread calls.
 
B

Bill Angus

I think there are a couple of different ways to do what you
want. I believe you could use a delegate function to update the
"splash_screen_form" from the other "main" form at different points as
main's initialization subroutine progresses. There is an
example of such a single-thread approach in the help file. I believe it
is in the progress bar example code... but the issue is the same.
One needs a progress-bar-dialog or splash-screen-dialog to get re-painted
properly and perhaps to remain
responsive to a control, while a lengthy process is going on. I can
post an example, but it would be just about a copy of what is in the
progressbar example code in the docs. NB it is necessary to make a call to
application.doevents() within the UIdelegate.
 
K

Kevin

Thanks for your replies guys:

Stephany: I dont have a problem that MS have fixed the cross-thread
'bug', although it is very annoying that it breaks my splash screen. I
do have a gripe that a) their built in method for splash screens is
absolute tripe, and b) they seem to have left me with no way to create
a form on a different thread that continuously updates whilst the main
GUI thread is busy. This was possible in 1.1 even if it wasnt
'correct'. I think you have missed my point; essentially what I need
is two GUI threads. I do have my own main module (which is the startup
method) that creates a splash screen, login screen, then the main form
etc, but what I am saying is the splash screen becomes upresponsive
whilst the main for is being created and initialised (because the GUI
thread is too busy creating the main form to repaint the splash
screen). My 1.1 code will not work with 2.0 no matter how many
delegates and invokes I use.

Bill: Thanks for your reply, I know the example you are talking about
but I dont think it helps me here.

To summarise, essentially what I require is two GUI threads, which does
not seem to be possible.

Thanks again
Kevin
 
J

Jon Skeet [C# MVP]

Kevin said:
Thanks for your replies guys:

Stephany: I dont have a problem that MS have fixed the cross-thread
'bug', although it is very annoying that it breaks my splash screen.

Your splash screen was broken beforehand - you were just being lucky.
You were doing things you were explicitly told not to do in the
documentation.
To summarise, essentially what I require is two GUI threads, which does
not seem to be possible.

You can have two GUI threads - but you need to be careful with them,
that's all.

Could you post a short but complete program which demonstrates the
problem?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.
 
K

Kevin

Thanks for your reply Jon, much appreciated.

I have posted a sample solution to:
http://www.kevinandkiran.com/splash_screen_tester.zip
It is in VB.

This is essentially my current solution, although interestingly I get
errors in different places to my actual program.
This seems to work about 90% of the time, although I am getting the
occaisional "Cross-thread operation not valid:" exceptions on line 40
(Label2.Text &= ".") of FormSplash, despite the fact that I have
invoked it.

I have also had to comment out line 21
(frmSplash.SetOwnerThreaded(frmMain)) of modMain as this too is causing
the exception. Strangely though my actual program allows this.

Line 11 should also really be frmLogin.ShowDialog(frmSplash) instead of
frmLogin.ShowDialog() so that the login screen appears in front of the
splash screen. Again, my program allows this.

Thanks again
Kevin
 
J

Jon Skeet [C# MVP]

Kevin said:
Thanks for your reply Jon, much appreciated.

I have posted a sample solution to:
http://www.kevinandkiran.com/splash_screen_tester.zip
It is in VB.

This is essentially my current solution, although interestingly I get
errors in different places to my actual program.
This seems to work about 90% of the time, although I am getting the
occaisional "Cross-thread operation not valid:" exceptions on line 40
(Label2.Text &= ".") of FormSplash, despite the fact that I have
invoked it.

I suspect that problem is because you've got a race condition - you can
end up calling InvokeRequired (and changing the status message) before
you've called ShowDialog - in other words, before you start the message
loop for that thread. You're also *creating* the splash screen on a
different thread to the one you're starting it on - that, again, sounds
like a bad idea.

There's also the problem that you're never running a message loop for
the splash screen as far as I can see.

I'm not an expert on this topic, but I would suggest that:

1) You only create a GUI control on the thread you're going to run it
on
2) You call Application.Run before calling Show.
I have also had to comment out line 21
(frmSplash.SetOwnerThreaded(frmMain)) of modMain as this too is causing
the exception. Strangely though my actual program allows this.

That sounds like a really bad idea (calling it, I mean). Setting the
owner of one form to be a form which has a different message thread
can't be a good idea, IMO.
Line 11 should also really be frmLogin.ShowDialog(frmSplash) instead of
frmLogin.ShowDialog() so that the login screen appears in front of the
splash screen. Again, my program allows this.

Hmm... not sure on this one.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Top