Re: Splash Screen - My Nemesis
Brady Kelly <[email protected]> Wed, 25 Jul 2007 22:48:34 +0200
| Newsgroups | gmane.comp.windows.devel.dotnet.winforms |
|---|---|
| Organization | Chase Software |
| Message-ID | <[email protected]> |
Thank you so much Andrew! This is the first code I've found tonight that
worked a anything like it should, and I all wanted to do was 'whip out a
splash screen quickly' for a small side project. Whew!
However, I have one problem: I'm using the splash screen to show while I
query a database during the form load event handler. If I get an error in
this method, the splash screen simply hangs. I tried adding a static
Abort() method to the Splash class, which works but I still get different
behaviours in the IDE and compiled.
First, in the IDE, I get my desired MessageBox, but it the compiled app
there is none. Here is my use of your code:
private void SearchGrid_Load(object sender, EventArgs e)
{
try
{
SplashManager.Show(this, typeof(SplashScreen), new
TimeSpan(0, 0, 0, 0, 500));
InitControls();
}
catch (Exception ex)
{
LogException(ex);
SplashManager.Abort();
MessageBox.Show(this, ex.Message, "Startup Error",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
Close();
}
finally
{
Cursor = Cursors.Default;
}
}
> -----Original Message-----
> From: Discussion forum for developers using Windows Forms to build apps
> and controls [mailto:[email protected]] On Behalf Of
> Eames, Andrew
> Sent: 25 July 2007 21:52 PM
> To: [email protected]
> Subject: Re: [DOTNET-WINFORMS] Splash Screen - My Nemesis
>
> I too found a lot of incorrect ways to implement a splash screen. Many
> of the public domain implementations I looked at had subtle bugs and/or
> race conditions in them too. I ended up writing the following code which
> you are welcome to borrow
> Andrew
> ------------------------------------------------------------------------
> ---------------------------------------------------------------
> /// <summary>
> /// Class that manages a splash screen
> /// </summary>
> public class SplashScreen
> {
> SplashScreen(Form parentForm, Type splashType, TimeSpan timeSpan)
> {
> parentForm_ = parentForm;
> splashType_ = splashType;
> timeSpan_ = timeSpan;
> culture_ = CultureInfo.CurrentCulture;
> parentForm.Shown += new EventHandler(OnParentShown);
> Thread t = new Thread(new ThreadStart(SplashThread));
> t.Start();
> }
>
> // This is the entry point for the thread that the splash screen
> runs on
> void SplashThread()
> {
> Thread.CurrentThread.CurrentCulture =
> Thread.CurrentThread.CurrentUICulture = culture_;
> splashForm_ = (Form)Activator.CreateInstance(splashType_);
> splashForm_.TopMost = true;
> splashForm_.ShowInTaskbar = false;
> splashForm_.FormBorderStyle = FormBorderStyle.FixedToolWindow; //
> prevents appearing in alt-TAB
> splashForm_.StartPosition = FormStartPosition.CenterScreen;
> splashForm_.HandleCreated += delegate {
> splashHandleCreated_.Set(); };
> using (System.Windows.Forms.Timer timer = new
> System.Windows.Forms.Timer())
> {
> timer.Interval = (int)timeSpan_.TotalMilliseconds;
> timer.Tick += delegate { timerExpired_ = true; MaybeClose(); };
> timer.Start();
> Application.Run(splashForm_);
> }
> }
>
> void MaybeClose()
> {
> // We don't close the splash screen until both the timer has
> expired and the main form has shown itself
> if (timerExpired_ && shown_)
> {
> // Note: We activate the parent form *before* closing the splash
> form, otherwise the windows paint
> // in a distracting way
> try
> {
> parentForm_.Invoke(new foo(delegate { parentForm_.Activate();
> }));
> }
> catch (InvalidOperationException)
> {
> // In case the parent has closed already!!
> }
> splashForm_.Close();
> splashHandleCreated_.Close();
> }
> }
> /// <summary>
> /// Executed on the splash form thread
> /// </summary>
> void OnParentShown()
> {
> shown_ = true;
> MaybeClose();
> }
>
> /// <summary>
> /// Raised on the thread of the main form
> /// </summary>
> /// <param name="sender"></param>
> /// <param name="e"></param>
> void OnParentShown(object sender, EventArgs e)
> {
> parentForm_.Shown -= new EventHandler(OnParentShown);
> // If the parent shows itself really quickly, its possible that
> the splash screen has
> // not yet created its window, which is why we use this event
> splashHandleCreated_.WaitOne();
> // Note we need to use BeginInvoke to avoid a potential deadlock
> since
> // the splash form may Invoke an activate right back at us
> splashForm_.BeginInvoke(new foo(OnParentShown));
> }
>
> /// <summary>
> ///
> /// </summary>
> /// <param name="parentForm"></param>
> /// <param name="splashType"></param>
> /// <param name="time"></param>
> public static void Show(Form parentForm, Type splashType, TimeSpan
> time)
> {
> new SplashScreen(parentForm, splashType, time);
> }
>
> TimeSpan timeSpan_;
> Type splashType_;
> Form parentForm_;
> Form splashForm_;
> CultureInfo culture_;
> ManualResetEvent splashHandleCreated_ = new ManualResetEvent(false);
> bool shown_;
> bool timerExpired_;
> }
>
> delegate void foo();
>
> -----Original Message-----
> From: Discussion forum for developers using Windows Forms to build apps
> and controls [mailto:[email protected]] On Behalf Of
> Brady Kelly
> Sent: Wednesday, July 25, 2007 3:39 PM
> To: [email protected]
> Subject: [DOTNET-WINFORMS] Splash Screen - My Nemesis
>
> Yes, I've just spent hours trying various examples that don't work, and
> I've
> just realised why people Callout actually _sell_ splash screen products.
> My
> biggest grip so far is that in the compiled app, not in the IDE, my main
> window, from which I display my splash screen, always appears in the
> background.
>
>
>
> My code is outrageously simple, with no status updates or anything:
>
>
>
> public SearchGridForm()
>
> {
>
> InitializeComponent();
>
> splashScreen = new SplashScreen();
>
> splashThread = new Thread(new ThreadStart(ShowSplash));
>
> splashThread.Start();
>
> }
>
>
>
> private void ShowSplash()
>
> {
>
> splashScreen.ShowDialog();
>
> }
>
>
>
> private void SearchGrid_Load(object sender, EventArgs e)
>
> {
>
> try
>
> {
>
> Cursor = Cursors.WaitCursor;
>
> InitControls();
>
> }
>
> finally
>
> {
>
> Cursor = Cursors.Default;
>
> splashThread.Abort();
>
> }
>
> }
>
>
> --
> BEGIN-ANTISPAM-VOTING-LINKS
> ------------------------------------------------------
>
> NOTE: This message was trained as non-spam. If this is wrong,
> please correct the training as soon as possible.
>
> Teach CanIt if this mail (ID 9056513) is spam:
> Spam:
> http://mail-gw.cognex.com/canit/b.php?c=s&i=9056513&m=08b08c6e418b
> Not spam:
> http://mail-gw.cognex.com/canit/b.php?c=n&i=9056513&m=08b08c6e418b
> Forget vote:
> http://mail-gw.cognex.com/canit/b.php?c=f&i=9056513&m=08b08c6e418b
> ------------------------------------------------------
> END-ANTISPAM-VOTING-LINKS