Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

.NET Splash Screen Component

0.00/5 (No votes)
23 Oct 2008 1  
A splash screen which allows for dynamic creation and updates.

Introduction

Well, after scouring the Internet for a free splash screen component for .NET, I was left quite unhappy. The only decent ones around were by a company called BitLaboratory, and another CodeProject article published by Mr. Tom Clemont (link).

I had used BitLab's component previously, and was not overwhelmed with its design ... and they would not release the source. :/

So, here I was in the middle of several projects which all needed a splash page. And, I'm not one for your basic static splash screen. I like to show the user what's going on in the background. So, here is my DGDev - a splash screen assembly.

Background

The basic ideas I wanted to implement:

  • Threading
  • Custom background image
  • Custom product/program information space
  • Custom space for updated status
  • Custom splash screen form shape (TransparencyKey)

Mr. Clemont's example served as a nice reference, but this has been entirely written from scratch.

Example

screenshot.jpg

  • ScreenCam for the project implementation: Click here.

Full code

The actual code is very short, and very clear to understand.

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

namespace DGDev
{
    public class SplashScreen : Form
    {
        private const double OpacityDecrement = .08;
        private const double OpacityIncrement = .05;
        private const int TimerInterval = 50;
        private static Boolean FadeMode;
        private static Boolean FadeInOut;
        private static Image BGImage;
        private static String Information;
        private static String Status;
        private static SplashScreen SplashScreenForm;
        private static Thread SplashScreenThread;
        private static Color TransparentKey;
        private Label ProgramInfoLabel;
        private Label StatusLabel;
        private System.Windows.Forms.Timer SplashTimer;
        private IContainer components;
        private delegate void UpdateLabel();
        private delegate void CloseSplash();

        #region Public Properties & Methods

        /// <summary>
        /// These methods can all be called to set configurable 
                  /// parameters for the Splash Screen
        /// </summary>
        public String SetInfo
        {
            get { return Information; }
            set
            {
                Information = value;
                if(ProgramInfoLabel.InvokeRequired)
                {
                    var InfoUpdate = 
                        new UpdateLabel(UpdateInfo);
                    Invoke(InfoUpdate);
                }
                else
                {
                    UpdateInfo();
                }
            }
        }

        public String SetStatus
        {
            get { return Status; }
            set
            {
                Status = value;
                if(StatusLabel.InvokeRequired)
                {
                    var StatusUpdate = 
                        new UpdateLabel(UpdateStatus);
                    Invoke(StatusUpdate);
                }
                else
                {
                    UpdateStatus();
                }
            }
        }

        public Image SetBackgroundImage
        {
            get { return BGImage; }
            set
            {
                BGImage = value;
                if (value != null)
                {
                    BackgroundImage = BGImage;
                    ClientSize = BackgroundImage.Size;
                }
            }
        }

        public Color SetTransparentKey
        {
            get { return TransparentKey; }
            set
            {
                TransparentKey = value;
                if (value != Color.Empty)
                    TransparencyKey = SetTransparentKey;
            }
        }

        public Boolean SetFade
        {
            get { return FadeInOut; }
            set
            {
                FadeInOut = value;
                Opacity = value ? .00 : 1.00;
            }
        }

        public static SplashScreen Current
        {
            get
            {
                if (SplashScreenForm == null)
                    SplashScreenForm = new SplashScreen();
                return SplashScreenForm;
            }
        }

        public void SetStatusLabel(Point StatusLabelLocation, 
                Int32 StatusLabelWidth, Int32 StatusLabelHeight)
        {
            if (StatusLabelLocation != Point.Empty)
                StatusLabel.Location = StatusLabelLocation;
            if (StatusLabelWidth == 0 && StatusLabelHeight == 0)
                StatusLabel.AutoSize = true;
            else
            {
                if (StatusLabelWidth > 0)
                    StatusLabel.Width = StatusLabelWidth;
                if (StatusLabelHeight > 0)
                    StatusLabel.Height = StatusLabelHeight;
            }
        }

        public void SetInfoLabel(Point InfoLabelLocation, 
                Int32 InfoLabelWidth, Int32 InfoLabelHeight)
        {
            if (InfoLabelLocation != Point.Empty)
                ProgramInfoLabel.Location = InfoLabelLocation;
            if (InfoLabelWidth == 0 && InfoLabelHeight == 0)
                ProgramInfoLabel.AutoSize = true;
            else
            {
                if (InfoLabelWidth > 0)
                    ProgramInfoLabel.Width = InfoLabelWidth;
                if (InfoLabelHeight > 0)
                    ProgramInfoLabel.Height = InfoLabelHeight;
            }
        }

        public void ShowSplashScreen()
        {
            SplashScreenThread = new Thread(ShowForm) 
                {IsBackground = true, Name = "SplashScreenThread"};
            SplashScreenThread.Start();
        }

        public void CloseSplashScreen()
        {
            if (SplashScreenForm != null)
            {
                if(InvokeRequired)
                {
                    var ClosingDelegate = 
                        new CloseSplash(HideSplash);
                    Invoke(ClosingDelegate);
                }
                else
                {
                    HideSplash();
                }
            }
        }
        #endregion

        public SplashScreen()
        {
            InitializeComponent();
        }

        private static void ShowForm()
        {
            Application.Run(SplashScreenForm);
        }

        private void UpdateStatus()
        {
            StatusLabel.Text = SetStatus;
        }

        private void UpdateInfo()
        {
            ProgramInfoLabel.Text = SetInfo;
        }

        private void SplashTimer_Tick(object sender, EventArgs e)
        {
            if(FadeMode) // Form is opening (Increment)
            {
                if (Opacity < 1.00)
                    Opacity += OpacityIncrement;
                else
                    SplashTimer.Stop();
            }
            else // Form is closing (Decrement)
            {
                if(Opacity > .00)
                    Opacity -= OpacityDecrement;
                else
                    Dispose();
            }
            
        }

        #region InitComponents

        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.ProgramInfoLabel = new System.Windows.Forms.Label();
            this.StatusLabel = new System.Windows.Forms.Label();
            this.SplashTimer = new System.Windows.Forms.Timer
                            (this.components);
            this.SuspendLayout();
            // 
            // ProgramInfoLabel
            // 
            this.ProgramInfoLabel.BackColor = 
                    System.Drawing.Color.Transparent;
            this.ProgramInfoLabel.Location = 
                    new System.Drawing.Point(56, 52);
            this.ProgramInfoLabel.Name = "ProgramInfoLabel";
            this.ProgramInfoLabel.Size = 
                    new System.Drawing.Size(100, 23);
            this.ProgramInfoLabel.TabIndex = 0;
            // 
            // StatusLabel
            // 
            this.StatusLabel.BackColor = 
                    System.Drawing.Color.Transparent;
            this.StatusLabel.Location = 
                    new System.Drawing.Point(59, 135);
            this.StatusLabel.Name = "StatusLabel";
            this.StatusLabel.Size = new System.Drawing.Size(100, 23);
            this.StatusLabel.TabIndex = 1;
            // 
            // SplashScreen
            // 
            this.ClientSize = new System.Drawing.Size(292, 273);
            this.Controls.Add(this.StatusLabel);
            this.Controls.Add(this.ProgramInfoLabel);
            this.FormBorderStyle = 
                System.Windows.Forms.FormBorderStyle.None;
            this.Name = "SplashScreen";
            this.ShowInTaskbar = false;
            this.StartPosition = 
                System.Windows.Forms.FormStartPosition.CenterScreen;
            this.ResumeLayout(false);

        }

        #endregion

        private void SplashScreen_Load(object sender, EventArgs e)
        {
            if (SetFade)
            {
                FadeMode = true;
                SplashTimer.Interval = TimerInterval;
                SplashTimer.Start();
            }
        }

        private void HideSplash()
        {
            if(SetFade)
            {
                FadeMode = false;
                SplashTimer.Start();
            }
            else
                Dispose();
        }
    }
}

Using the DLL

Let's take a quick glimpse at another program I'm working on, which is now fit for using the splash screen.

Program.cs

using System;
using System.Drawing;
using System.Windows.Forms;
using DGDev;

namespace Raum
{
    static class Program
    {
        private static SplashScreen splash;

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            const String resourceName = "Splash.png";
            var InfoLabel = new Point(25, 92);
            var StatusLabel = new Point(28, 261);

            splash = SplashScreen.Current;
            splash.SetTransparentKey = Color.Fuchsia;
            var rs = GetResourceStream(resourceName);
            splash.SetBackgroundImage = new Bitmap(rs);
            splash.SetInfoLabel(InfoLabel, 499, 117);
            splash.SetStatusLabel(StatusLabel, 490, 17);
            splash.ShowSplashScreen();
            splash.SetInfo = "This program is just an example.";

            AppDomain currentDomain = AppDomain.CurrentDomain;
            currentDomain.AssemblyLoad += asmLoadHandler;

            Application.Run(new RaumMain());
        }

        private static System.IO.Stream GetResourceStream(String resource)
        {
            var ea = System.Reflection.Assembly.GetExecutingAssembly();
            foreach (String curResource in ea.GetManifestResourceNames())
            {
                if (curResource.EndsWith(resource))
                {
                    return ea.GetManifestResourceStream
                                (curResource);
                }
            }
            return null;
        }

        static void asmLoadHandler(object sender, AssemblyLoadEventArgs args)
        {
            splash.SetStatus = "Loading Assembly: " + 
                args.LoadedAssembly.GetName().Name + " ...";
        }
    }
}

A closer look

So, what's going on up there?!? By using this SplashScreen.dll, you can literally have your splash screen done in a minute, with several options to play with.

// This will be our BackgroundImage of the Splash
const String resourceName = "Splash.png";  
// This creates a Location point for our ProgramInfo label.
var InfoLabel = new Point(25, 92);  
// This creates a Location point for our Status label.
var StatusLabel = new Point(28, 261);  

// You must call this before attempting to assign any properties! 
// It creates/initializes all the form controls. 
splash = SplashScreen.Current; 

// Say you want a custom shape Splash Screen. 
// You can use this to set the TransparencyKey. 
splash.SetTransparentKey = Color.Fuchsia; 

// Call our function to pull the image from our Resources.resx
var rs = GetResourceStream(resourceName); 
// Set the Splash BackgroundImage
splash.SetBackgroundImage = new Bitmap(rs); 

//This method uses 3 parameters. (Point Location, Int32 Width, Int32 Height)
//If you set both Width & Height to 0, than the label will set AutoSize = true. 
//Default is false.

splash.SetInfoLabel(InfoLabel, 499, 117);

splash.SetStatusLabel(StatusLabel, 490, 17); // Same as above, but for the Status Label

splash.ShowSplashScreen();  // You must call this to RUN the Splash Screen 
splash.SetInfo = "This program is just an example.";

Dynamically loading updates

By preference, I like to show the user what .NET assemblies are being loaded. Here, we see that whenever an assembly is loaded, it updates the status label on the splash screen.

AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyLoad += asmLoadHandler;

static void asmLoadHandler(object sender, AssemblyLoadEventArgs args)
{
    splash.SetStatus = "Loading Assembly: " + 
            args.LoadedAssembly.GetName().Name + " ...";
}

Closing the splash screen

A great feature about this class is that it can be accessed from anywhere in your code. So, after your Main form has loaded, just use the following to close the splash screen:

splash = SplashScreen.Current;
splash.CloseSplashScreen();

Points of interest

Known issues:

  • When using a custom shape form/TransparencyKey, you cannot use the SetFade property. If you do, you'll notice that the TransparencyKey does not work until the Form.Opacity is at 1.00.

Questions/Problems/Suggestions

I have not yet implemented try/catch blocks, so exceptions are not being handled at the moment. Will do more testing, and add new features along with proper exception handling.

If you have a problem, feel free to email me, or post in the discussion forum below.

If you're using this for proprietary commercial software, help a broke college student out and donate a dollar.

History

  • 10.13.2008 - v1.0.0.0 released.
  • 10.24.2008 2:05pm - Fixed the demo download link. Sorry guys.
  • 10.23.2008 4:42pm - Uploaded new files. There were a few bugs to be fixed. Code should now work with all .NET Framework versions. Also, the SetFade is fixed.
  • 10.13.2008 10:08pm - Sorry guys, after refactoring the code automatically with JetBrains, it took away some needed assembly constructors in the designer code. Reshaper tends to think everything is redundant, sometimes. I've updated the fixed file.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here