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