Re: Splash Screen - My Nemesis

"Eames, Andrew" <[email protected]> Thu, 26 Jul 2007 09:22:18 -0400
Newsgroups gmane.comp.windows.devel.dotnet.winforms
Message-ID <[email protected]>
My class assumes the parent form will actually be "shown" (and raise the
Shown event). To handle your case, you'll need to extend the class to
add a handler to the parent's Closed event too so the splash thread will
terminate if the parent is closed but not shown.

(BTW, aborting threads, while convenient, is not generally good
practice)
  Andrew

-----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 4:49 PM
To: [email protected]
Subject: Re: [DOTNET-WINFORMS] Splash Screen - My Nemesis

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
------------------------------------------------------

Teach CanIt if this mail (ID 9057094) is spam:
Spam:
http://mail-gw.cognex.com/canit/b.php?c=s&i=9057094&m=17d7814d87e4
Not spam:
http://mail-gw.cognex.com/canit/b.php?c=n&i=9057094&m=17d7814d87e4
Forget vote:
http://mail-gw.cognex.com/canit/b.php?c=f&i=9057094&m=17d7814d87e4
------------------------------------------------------
END-ANTISPAM-VOTING-LINKS