Since VB 2005, VB.NET has provided something called the Application Framework, which lets you configure certain application characteristics with a few clicks. One of those characteristics is the splash screen for the application. Displaying a splash screen is not as straightforward as it may first appear. The VB Application Framework creates the splash screen on a secondary thread, so that it doesn't interfere with the main form. It will also keep the splash screen open for a minimum amount of time, even if the main form takes less time to be ready to display. If the main form is not ready within that time, the splash screen will remain open until it is.

The code below provides that same behaviour in a C# application. Add a form to your application to use as a splash screen and add the following code:
csharp Code:
  1. using System;
  2. using System.Threading;
  3. using System.Windows.Forms;
  4. using Timer = System.Timers.Timer;
  5.  
  6. namespace Multi_threaded_Splash_Screen
  7. {
  8.     public partial class SplashScreen : Form
  9.     {
  10.         /// <summary>
  11.         /// Contains information for creating a splash screen.
  12.         /// </summary>
  13.         private struct SplashScreenInfo
  14.         {
  15.             /// <summary>
  16.             /// The main form for the application.
  17.             /// </summary>
  18.             public Form StartupForm;
  19.             /// <summary>
  20.             /// The minimum number of milliseconds for which to display the splash screen.
  21.             /// </summary>
  22.             public int MinimumDisplayTime;
  23.             /// <summary>
  24.             /// Signals the main thread when a handler has been added to the main form's Load event.
  25.             /// </summary>
  26.             public ManualResetEvent Handle;
  27.         }
  28.  
  29.         /// <summary>
  30.         /// Tells the splash screen when it has been open for the minimum amount of time.
  31.         /// </summary>
  32.         private Timer timer = new Timer();
  33.         /// <summary>
  34.         /// The minimum number of milliseconds for which to display the splash screen.
  35.         /// </summary>
  36.         private bool minimumDisplayTimeExpired = false;
  37.         /// <summary>
  38.         /// Used to synchronise multiple threads.
  39.         /// </summary>
  40.         private object syncRoot = new object();
  41.         /// <summary>
  42.         /// Signals the main thread when the splash screen is ready to close.
  43.         /// </summary>
  44.         private ManualResetEvent closeHandle;
  45.  
  46.         /// <summary>
  47.         /// Creates a new instance of the SplashScreen class.
  48.         /// </summary>
  49.         /// <param name="startupForm">
  50.         /// The main form for the application.
  51.         /// </param>
  52.         /// <param name="minimumDisplayTime">
  53.         /// The minimum number of milliseconds for which to display the splash screen.
  54.         /// </param>
  55.         private SplashScreen(Form startupForm, int minimumDisplayTime)
  56.         {
  57.             InitializeComponent();
  58.  
  59.             // We need to know when the main form is ready to be displayed.
  60.             startupForm.Load += startupForm_Load;
  61.  
  62.             // We need to know when the splash screen is ready to be dismissed.
  63.             timer.Elapsed += timer_Elapsed;
  64.             timer.Interval = minimumDisplayTime;
  65.             timer.Start();
  66.         }
  67.  
  68.         /// <summary>
  69.         /// Displays a splash screen.
  70.         /// </summary>
  71.         /// <param name="startupForm">
  72.         /// The main form for the application.
  73.         /// </param>
  74.         /// <param name="minimumDisplayTime">
  75.         /// The minimum number of milliseconds for which to display the splash screen.
  76.         /// </param>
  77.         public static void DisplaySplashScreen(Form startupForm, int minimumDisplayTime)
  78.         {
  79.             var continueHandle = new ManualResetEvent(false);
  80.  
  81.             // Create and display the splash screen on a secondary thread.
  82.             new Thread(DisplaySplashScreen).Start(new SplashScreenInfo
  83.                                                       {
  84.                                                           StartupForm = startupForm,
  85.                                                           MinimumDisplayTime = minimumDisplayTime,
  86.                                                           Handle = continueHandle
  87.                                                       });
  88.  
  89.             // The handler must be added to the main form's Load event before the main thread can safely continue.
  90.             continueHandle.WaitOne();
  91.         }
  92.  
  93.         /// <summary>
  94.         /// Displays a splash screen.
  95.         /// </summary>
  96.         /// <param name="info">
  97.         /// Contains information for creating a splash screen.
  98.         /// </param>
  99.         private static void DisplaySplashScreen(object info)
  100.         {
  101.             var ssi = (SplashScreenInfo) info;
  102.             var splashScreen = new SplashScreen(ssi.StartupForm, ssi.MinimumDisplayTime);
  103.  
  104.             // The main form's Load event has been handled so the main thread can safely continue.
  105.             ssi.Handle.Set();
  106.  
  107.             // Display the splash screen.
  108.             Application.Run(splashScreen);
  109.         }
  110.  
  111.         private void startupForm_Load(object sender, EventArgs e)
  112.         {
  113.             lock (syncRoot)
  114.             {
  115.                 if (!minimumDisplayTimeExpired)
  116.                 {
  117.                     // The splash screen is not ready to be dismissed so we must make the main form wait.
  118.                     closeHandle = new ManualResetEvent(false);
  119.                 }
  120.             }
  121.  
  122.             if (closeHandle != null)
  123.             {
  124.                 // The splash screen is not ready to be dismissed so we must make the main form wait.
  125.                 closeHandle.WaitOne();
  126.             }
  127.  
  128.             // Close the splash screen and allow the main form to be displayed.
  129.             this.Invoke(new MethodInvoker(this.Close));
  130.         }
  131.  
  132.         private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
  133.         {
  134.             lock (syncRoot)
  135.             {
  136.                 if (closeHandle == null)
  137.                 {
  138.                     // The splash screen is ready to be dismissed before the main form is ready to be displayed.
  139.                     // Allow the main form to be displayed as soon as it is ready.
  140.                     minimumDisplayTimeExpired = true;
  141.                 }
  142.                 else
  143.                 {
  144.                     // The main form is already ready to be displayed and is waiting for the splash screen.
  145.                     closeHandle.Set();
  146.                 }
  147.             }
  148.         }
  149.     }
  150. }
You may need to change the namespace and, if you didn't name the form "SplashScreen", the class name. Now go to the Program.cs code file and change your Main method to look something like this:
csharp Code:
  1. /// <summary>
  2. /// The main entry point for the application.
  3. /// </summary>
  4. [STAThread]
  5. static void Main()
  6. {
  7.     Application.EnableVisualStyles();
  8.     Application.SetCompatibleTextRenderingDefault(false);
  9.  
  10.     var mainWindow = new MainWindow();
  11.  
  12.     SplashScreen.DisplaySplashScreen(mainWindow, 3000);
  13.  
  14.     Application.Run(mainWindow);
  15. }
Again, change the class name(s) if they don't match your own. Now run the project and you'll see your splash screen displayed for at least 3 seconds and then it will disappear and your startup form will be displayed. If the startup form takes longer than that minimum of 3 seconds to be ready to display then the splash screen will stay open as long as it takes. You can test this by adding a Load event handler to the startup form and calling Thread.Sleep with a value greater than 3000, e.g. 10,000. You can change the minimum time by passing a different value to the second parameter of DisplaySplashScreen.