Re: Splash Screen - My Nemesis

Peter Osucha <[email protected]> Wed, 25 Jul 2007 16:49:15 -0400
Newsgroups gmane.comp.windows.devel.dotnet.winforms
Message-ID <[email protected]>
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();

            }

        }