Re: Splash Screen - My Nemesis

"Eames, Andrew" <[email protected]> Wed, 25 Jul 2007 15:52:25 -0400
Newsgroups gmane.comp.windows.devel.dotnet.winforms
Message-ID <[email protected]>
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