Re: Splash Screen - My Nemesis

Brady Kelly <[email protected]> Wed, 25 Jul 2007 22:55:22 +0200
Newsgroups gmane.comp.windows.devel.dotnet.winforms
Organization Chase Software
Message-ID <[email protected]>
Peter, I don't mind the main form not showing until the splash screen goes
away, but until trying Andrew's example my main form was going to the
background _when_ the splash screen went away.  So the user would be
watching the splash, and then, if I'm lucky[1], looking for the main form
behind something else.


[1] I'm not lucky - I've even been briefed to deploy only a single file as
the client worries about users clicking the wrong files to runt the app.

> -----Original Message-----
> From: Discussion forum for developers using Windows Forms to build apps
> and controls [mailto:[email protected]] On Behalf Of
> Peter Osucha
> Sent: 25 July 2007 22:49 PM
> To: [email protected]
> Subject: Re: [DOTNET-WINFORMS] Splash Screen - My Nemesis
>
> OK, then at least I'm calling it correctly.  Perhaps I didn't understand
> what Brady desired (which I thought was that the main form not show even
> in the background until the splash screen went away).
>
> Thanks for the confirmation of the call, though.
>
> Peter
>
>
> -----Original Message-----
> From: Discussion forum for developers using Windows Forms to build apps
> and controls [mailto:[email protected]] On Behalf Of
> Eames, Andrew
> Sent: Wednesday, July 25, 2007 4:39 PM
> To: [email protected]
> Subject: Re: [DOTNET-WINFORMS] Splash Screen - My Nemesis
>
> Yes - There's only 1 public method so only 1 way to use it:)
>
> e.g.
>
> parentForm = new MainForm();
> SplashScreen.Show(parentForm,typeof(mySplashScreen),TimeSpan.FromSeconds
> (3));
> Application.Run(paentForm);
>
> Andrew
>
> -----Original Message-----
> From: Discussion forum for developers using Windows Forms to build apps
> and controls [mailto:[email protected]] On Behalf Of
> Peter Osucha
> Sent: Wednesday, July 25, 2007 4:32 PM
> To: [email protected]
> Subject: Re: [DOTNET-WINFORMS] Splash Screen - My Nemesis
>
> Andrew,
>
> Anytime I see a splash screen example, I look at it closely (hence, my
> jumping in to this discussion).  To be honest, I can't figure out how to
> use the code you suggest below.
>
> It is apparent (I think!) that the intent is to call the static method
> of this class to show the splash screen, presumably from the Main()
> method of the application.  That doesn't seem to work for me however.
> Is that the intent?
>
> Peter
>
> -----Original Message-----
> From: Discussion forum for developers using Windows Forms to build apps
> and controls [mailto:[email protected]] On Behalf Of
> Eames, Andrew
> Sent: Wednesday, July 25, 2007 3: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();
>
>             }
>
>         }