Click here to Skip to main content
Click here to Skip to main content

Splash Form and Loading Data in a Separate Thread

, 7 Apr 2006 CPOL
Rate this:
Please Sign up or sign in to vote.
How to display a splash form and load data in a separate thread
image 1

image 2

Introduction

I believe every application developer has experienced the problem with slow loading user interface because loading data takes too much time.

While for Web applications, it might seem more natural because of generating the page on the fly, using slow internet connection or overloaded server, it is not the case for Windows Forms applications. They run locally on your machine and it is expected to be more responsive. Still too often, you can see applications that take too much time to update the user interface and display the data.

This article will try to show you how to make a Windows Forms application more responsive by showing the user interface while waiting for the data and updating the interface when data is available.

The article demonstrates few things:

  • How to build a splash form to be displayed during a time consuming operation
  • Performing the time consuming operation in a separate thread
  • Center the splash form relative to main form
  • Move the splash screen when the main form is moved to keep it centered to it
  • Hide / show the splash screen when the main form gets / loses focus

The solution consists of two forms:

  • MainForm - This is the main form as the name suggests
  • SplashFrm - The splash form

MainForm

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Threading;

namespace SplashScreen
{
  /// <summary>
  /// Summary description for MainForm.
  /// </summary>
  public class MainForm : System.Windows.Forms.Form
  {
    private System.ComponentModel.Container components = null;
    private System.Windows.Forms.Label label1;
    private System.Windows.Forms.StatusBar statusBar1;

    // instance member to keep reference to splash form
    private SplashForm frmSplash;

    // delegate for the UI updater
    public delegate void UpdateUIDelegate(bool IsDataLoaded);

    //
    // Some of the code was removed for simplicity
    //

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
      Application.Run(new MainForm());
    }

    /// <summary>
    /// Handles the Load event of the MainForm control.
    /// </summary>
    private void MainForm_Load(object sender, System.EventArgs e)
    {
      // Update UI
      UpdateUI(false);

      // Show the splash form
      frmSplash = new SplashForm(this);

      // Do some time consuming work in separate thread
      Thread t = new Thread(new ThreadStart(DoSomeWork));
      t.IsBackground = true;
      t.Start();
    }

    /// <summary>
    /// Time consuming method
    /// </summary>
    private void DoSomeWork()
    {
      // This is time consuming operation - loading data, etc.
      System.Threading.Thread.Sleep(10000);

      // Update UI
      Invoke(new UpdateUIDelegate(UpdateUI), new object[] { true });
    }

    /// <summary>
    /// Updates the UI.
    /// </summary>
    private void UpdateUI(bool IsDataLoaded)
    {
      if (IsDataLoaded)
      {
        this.statusBar1.Text = "Done.";

        // close the splash form
        if (this.frmSplash != null) {
          frmSplash.Close();
        }
      }
      else
      {
        this.statusBar1.Text = "Loading data ...";
      }
    }
  }
}

The code is very straightforward. At the time the main form is loaded, the UpdateUI() method is invoked to update the status bar. Then the splash form is shown and immediately after that, DoSomeWork() method is executed in a separate thread.

By using this technique, the main form is displayed without any delay and the splash form is telling the user that the data is loading. If we do not use a separate thread to load the data, it might take a few seconds for the main form to appear. It is all about the user experience.

When the data is loaded, we have to update the user interface - change the status bar text and close the splash form. Since loading of the data happened in a separate thread, we are not supposed to update the main form directly. Instead, we are going to use the main form's Invoke method passing the delegate to UpdateUI() method with a parameter telling the data loading is complete.

Now let's have a look at the splash form.

SplashForm

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;

namespace SplashScreen
{
  /// <summary>
  /// Summary description for SplashForm.
  /// </summary>
  public class SplashForm : System.Windows.Forms.Form
  {
    private System.Windows.Forms.Panel panel1;
    private System.Windows.Forms.Label label1;
    private System.ComponentModel.Container components = null;

    // instance member to keep a reference to main form
    private Form MainForm;

    // flag to indicate if the form has been closed
    private bool IsClosed = false;

    #region Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="SplashForm" /> class.
    /// </summary>
    public SplashForm()
    {
      InitializeComponent();
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="SplashForm" /> class.
    /// </summary>
    public SplashForm(Form mainForm):this() {
      // Store the reference to parent form
      MainForm = mainForm;

      // Attach to parent form events
      MainForm.Deactivate += new System.EventHandler(this.MainForm_Deactivate);
      MainForm.Activated += new System.EventHandler(this.MainForm_Activated);
      MainForm.Move += new System.EventHandler(this.MainForm_Move);

      // Adjust appearance
      this.ShowInTaskbar = false; // do not show form in task bar
      this.TopMost = true; // show splash form on top of main form
      this.StartPosition = FormStartPosition.Manual;
      this.Visible = false;

      // Adjust location
      AdjustLocation();
    }

    #endregion

    #region Methods

    private void MainForm_Deactivate(object sender, EventArgs e)
    {
      if (!this.IsClosed)
      {
        this.Visible = false;
      }
    }

    private void MainForm_Activated(object sender, EventArgs e)
    {
      if (!this.IsClosed)
      {
        this.Visible = true;
      }
    }

    private void MainForm_Move(object sender, EventArgs e)
      {
        // Adjust location
        AdjustLocation();
      }

    private void SplashForm_Closed(object sender, System.EventArgs e)
    {
      this.IsClosed = true;
    }

    private void AdjustLocation()
      {
        // Adjust the position relative to main form
        int dx = (MainForm.Width - this.Width) / 2;
        int dy = (MainForm.Height - this.Height) / 2;
        Point loc = new Point(MainForm.Location.X, MainForm.Location.Y);
        loc.Offset(dx, dy);
        this.Location = loc;
      }

    #endregion
  }
}

In addition to the default constructor, we have another one that accepts as a parameter a reference to the main form. We are using this one inside MainForm_Load():

  // Show the splash form
  frmSplash = new SplashForm(this);
  frmSplash.Show();  

We need the main form reference in order to be able to adjust the position of splash form and its visibility when those change for the main form.

That's all about it.

Conclusion

I would be glad if this article helps someone trying to provide a better user experience for WinForm applications. I am open to any suggestions or questions.

Known Issues

The solution is still not perfect. If you start another application, the main form will lose focus and the splash form will be hidden. However, if you minimize that other application and main form gets visible, the splash form will not show unless you click the main form giving the focus to it in this way.

History

  • 29th March, 2006 - Initial version
  • 7th April, 2006 - Show/hide splash form when main form gets / loses focus; splash form follows main form when the latter is moved across the screen

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

anichin
Web Developer
Canada Canada
Angel Anichin is experienced .Net developer living in Canada.
 
Expertise: ASP.NET, C#, MS Content Management Server, MS SQL Server, Oracle, HTML, JavaScript, CSS
 
Hobbies: Digital Photography, Skiing
Follow on   LinkedIn

Comments and Discussions

 
GeneralInterrupt thread since SplashForm Pinmembergil1312-Jan-09 4:37 
GeneralThis is not going to work correctly... PinmemberTim McCurdy4-Apr-06 4:40 
GeneralRe: This is not going to work correctly... Pinmemberanichin4-Apr-06 19:27 
GeneralRe: This is not going to work correctly... Pinmemberanichin7-Apr-06 10:51 
GeneralAdd some more introduction PinmemberSiddharth197529-Mar-06 19:41 
GeneralRe: Add some more introduction Pinmemberanichin29-Mar-06 19:51 
GeneralRe: Add some more introduction Pinmemberanichin7-Apr-06 10:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141220.1 | Last Updated 7 Apr 2006
Article Copyright 2006 by anichin
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid