I am optimizing the startup of a WinForms app. One issue I identified is the loading of the splash screen form. It takes about half a second to a second.
I know that multi-threading is a no-no on UI pieces, however, seeing how the splash screen is a fairly autonomous piece of the application, is it possible to somehow mitigate its performance hit by throwing it one some other thread (perhaps in the way Chrome does it), so that the important pieces of the application can actually get going.
A splash screen is a graphical control element consisting of a window containing an image, a logo, and the current version of the software. A splash screen can appear while a game or program is launching.
“Alternatively referred to as a boot screen, boot skin, or welcome screen, the splash screen is an introduction page that is displayed as a program or computer is loading or booting. Typically the splash screen can include a logo or other image, as well as a company name, and sometimes the company's slogan.”
The .NET framework already has very good support for splash screens in Windows Forms apps. Check this thread for a code sample. It is indeed optimized for warm startup time, it makes sure the splash thread and screen is up and running before initializing the main app.
There's nothing to be gained from spawning a thread if your goal is to get the splash screen up as quickly as possible.
There are several ways to do splash screens, and a more sophisticated one is mentioned here, but this is an easy method I have used with complete success:
Just ensure you load and show the splash form first, and then continue to load your app while the user is looking at the pretty splash screen. When the mainform is done loading, it can close the splash right before it shows itself (a simple way to do this is pass the splash form to the mainform in its constructor):
static void Main()
{
Application.SetCompatibleTextRenderingDefault(false);
SplashForm splash = new SplashForm();
splash.Show();
splash.Refresh(); // make sure the splash draws itself properly
Application.EnableVisualStyles();
Application.Run(new MainForm(splash));
}
public partial class MainForm : Form
{
SplashForm _splash;
public MainForm(SplashForm splash)
{
_splash = splash;
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
// or do all expensive loading here (or in the constructor if you prefer)
_splash.Close();
}
}
Alternative: If you prefer not to pass the splash to the MainForm (maybe it seems inelegant), then subscribe to the MainForm's Load event, and close the splash screen there:
static class Program
{
static SplashForm _splash;
[STAThread]
static void Main()
{
Application.SetCompatibleTextRenderingDefault(false);
_splash = new SplashForm();
_splash.Show();
_splash.Refresh();
Application.EnableVisualStyles();
MainForm mainForm = new MainForm();
mainForm.Load += new EventHandler(mainForm_Load);
Application.Run(mainForm);
}
static void mainForm_Load(object sender, EventArgs e)
{
_splash.Dispose();
}
}
As mentioned in this thread, the potential downside to this solution is that the user won't be able to interact with the splash screen. However, that usually isn't required.
Multithreading in WinForms is okay as long as all the UI stays on one thread.
This is just how splash screens are usually done. The important work is done on a background thread, while the splash screen window is shown on the UI thread to let the user know that the rest of the program will appear soon.
After the important stuff has happened, raise an event to let the UI thread know that it is time to hide the splash screen (just remember to marshal the event handler, using Invoke(), back onto the UI thread in order to close the splash screen).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With