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

.NET Splash Screen Component

By , 23 Oct 2008
 

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, along with any associated source code and files, is licensed under The Creative Commons Attribution-ShareAlike 2.5 License

About the Author

Anon1234567890
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Questionre-Show the ScreenPlashmemberBlowdesign23 Nov '09 - 3:47 
Hello,
 
This is a nice control. Thanks you.
 
I've a litte problem, i've a form who's slow to be loaded because I've a lot of control created dynamically. I would like to re-show the splashscreen when this page is loading but it's not possible because the splashscreen is disposed.
 
Who can i make to re-show the splashscreen and change the status whit "loading control x of y", etc ?
 
Thanks in advance.
AnswerRe: re-Show the ScreenPlashmemberDGDev23 Nov '09 - 5:00 
Unfortunately, there is no current way to do this without re-creating the splash screen. As you stated, calling CloseSplashScreen() will dispose of the object. What's needed is a HideSplashScreen() method.
 
To update the status text, check out: UpdateControlText[^]
 
This is very easy to implement and I will do so when I get home from work.
 
DGDev

QuestionRe: re-Show the ScreenPlashmemberBlowdesign24 Nov '09 - 23:42 
Thank you for your answer. But i don't see why y can do that. Could you explain me ?
 
Thanks in advance.
GeneralError when starting project after crashmemberdauciunas11 Nov '09 - 3:24 
Hi,
 
i get this error :
Cross-thread operation not valid:
Control 'ProgramInfoLabel' accessed from a thread other than the thread it was created on.
 
at this point:
private void UpdateInfo()
{
------------->>>>>>>>> ProgramInfoLabel.Text = SetInfo;
}
 
Strange thing about it that it only appears after Visual Studio crash or smth similar
and i get rid of it by doing "clear project" and re-run`ing the project again.
 
Have no idea how to fix this.
Can You help ?
GeneralRe: Error when starting project after crashmemberDGDev11 Nov '09 - 5:32 
I don't recommend using this article's code.
Here is a much improved SplashScreen component:
Advanced Splash Screen
 
You can view the documentation here: Documentation
 
DGDev

GeneralRe: Error when starting project after crashmemberdauciunas11 Nov '09 - 11:17 
Thanx Smile | :)
This one works very nice Smile | :)
GeneralTerminating the splash screenmemberImpero10116 Sep '09 - 8:49 
If a user wish to terminate the program during the splash screen, how can this be implemented?
Generalok articlememberDonsw4 Feb '09 - 5:31 
It might be nice to explain some of the code instead of just posting some of the code. The code is nice but others might want to learn of what were your problems along the way or what you found difficult.
GeneralRe: ok articlememberDGDev4 Feb '09 - 20:19 
Will try to do that in the future...
However I do not suggest following this article anymore.
 
Please visit:
http://www.dgdev.net/products/software/advanced-splash-screen-component-for-net/[^]
 
This is a complete redo of the Splash Screen component and is far better. I will be implementing a few new features to it as well in the coming days...
 
It's 100% FREE, but I do accept any donations if you think its well deserved.
You can find thorough documentation within the download zip file and online at:
 
http://www.dgdev.net/documentation/advancedsplashscreen/[^]
 
Select the "Enterprise" edition to obtain the zip which contains the VS project files and source code.
 
Thanks again everyone for your responses and email me with any questions at daniel@dgdev.net
 
DGDev

GeneralSTOP USING THIS COMPONENT! [modified]memberDGDev16 Dec '08 - 14:13 
...
Please go here for details:
Here is a much improved SplashScreen component:
Advanced Splash Screen
 
You can view the documentation here: Documentation
 
DGDev
modified on Wednesday, November 11, 2009 11:33 AM

GeneralRe: STOP USING THIS COMPONENT!memberLery782 Jul '09 - 8:07 
Hi, I was looking for your example but I can see the page.
Do you have any idea what matter?
thank you
GeneralRe: STOP USING THIS COMPONENT!memberDGDev11 Nov '09 - 5:32 
Here is a much improved SplashScreen component:
Advanced Splash Screen
 
You can view the documentation here: Documentation
 
DGDev

GeneralRe-use splashmemberDennis Sheppard5 Dec '08 - 8:18 
I want to be able to use a splash screen at load, and then again at another point when I need it.
 
If I just use splash.CloseSplashScreen() and then later try to use splash.ShowSplashScreen() I get an error: "Cannot access a disposed object. Object name: 'SplashScreen'."
 
I've also tried creating to separate SplashScreen objects and doing something like splash1.CloseSplashScreen() and then later splash2.ShowSplashScreen().... but I get the same error.
 
Ideas?
 
Thanks!
GeneralThis is very nice!memberdataporter2 Nov '08 - 9:34 
Well Done!!
 
Thank You!
QuestionWinapp Main form hiding behind another open windowmemberokash23 Oct '08 - 23:25 
The video shows that the Main form of the Wondows app hides behind another window. Same problem with the splash screen I am using (different at the momment). Is there any solution for this?
 
asdf

AnswerRe: Winapp Main form hiding behind another open windowmemberDGDev24 Oct '08 - 8:15 
This has already been resolved.
 
Please use this code snippet in your main form.
 
Activate();
splash.CloseSplashScreen();
 
DGDev

Generaldemo project broken linkmemberMichal Stehlik23 Oct '08 - 22:33 
your link to demo project is broken, fix it asap
GeneralRe: demo project broken linkmemberDGDev24 Oct '08 - 8:15 
Fixed...
Sorry for the trouble.
 
DGDev

GeneralFadememberlagdaemon23 Oct '08 - 9:40 
I have VS2008 SP1.
 
I tried to turn on the Fade in the demo and the spash screen never shows. I have looked over the code and can not see anything wrong, it should fade in and out.
 
BTW:
 
Nicely done Smile | :)
 
Bill
GeneralRe: FadememberDGDev23 Oct '08 - 10:52 
Thanks for pointing this out. I've no idea why two event handlers were never set. One for form_load ... the other for SplashTimer.Tick
 
Please re-download the files guys.
 
DGDev

QuestionThis Part did not workmembermaabd22 Oct '08 - 16:37 
the below code never called, WHY ?
 
static void asmLoadHandler(object sender, AssemblyLoadEventArgs args)
{
splash.SetStatus = "Loading Assembly: " + args.LoadedAssembly.GetName().Name + " ...";
}
 
if I m asking i want to learn more and not to play, i like computer programming and advanced feature i can use.
so don't undertand my message wrongly for any reson
thanks

AnswerRe: This Part did not workmemberDGDev22 Oct '08 - 16:55 
It is called as long as you setup the event handler:
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyLoad += asmLoadHandler;
 
It probably won't show it in the Demo splash screen application.
This is because we're setting the event handler after the Splash Screen has been created and initialized. But by the time that happens, the .net assemblies that are used have already been loaded.
 
If you'd like to see it in use, add it to program which makes use of several libraries.
 
DGDev

QuestionWPF ?memberLoic Berthollet21 Oct '08 - 2:19 
Very fast & simple. Great job. Got my 5.
 
Have you tried it with a WPF application?
Is it so fast?
 
Regards
 
Loïc Berthollet

GeneralNo demo project and no screenshotmemberJohnny J.13 Oct '08 - 21:15 
?????
GeneralRe: No demo project and no screenshotmemberDGDev13 Oct '08 - 23:50 
Understandable ...
Hopefully the information provided now will help you out. I've uploaded a demo and screenshot.
 
DGDev

GeneralRe: No demo project and no screenshotmemberJohnny J.14 Oct '08 - 0:43 
Thanks a lot. It looks great. I will definitely have a closer look at the component.
 
I noticed one problem with your demo, though. And since it's a problem I have from time to time with my applications without being able to explain it, I thought I'd ask the rest of the members if they have an explanation:
 
Once the splash form is closed, you'd assume that the application itself would be active, right?
 
But after the splash screen closes, the application is sent to the back of the ZOrder and some other application that's open at the time gets the focus.
 
WHY IS THAT?
 
TIA, Johnny J.
GeneralRe: No demo project and no screenshot [modified]memberDGDev14 Oct '08 - 0:49 
Well I just noticed a snippet of code from Tom Clemont's article...
 
private void Form1_Layout(object sender, System.Windows.Forms.LayoutEventArgs e)
{
if( m_bLayoutCalled == false )
{
m_bLayoutCalled = true;
m_dt = DateTime.Now;
if( SplashScreen.SplashForm != null )
SplashScreen.SplashForm.Owner = this;
this.Activate();
SplashScreen.CloseForm();
timer1.Start();
}
}
 
You can try using:
 
if(splash.Current != null)
splash.Owner = this;
Activate();
splash.CloseSplashScreen();
 
I'll test this out in a minute...
 
DGDev
modified on Tuesday, October 14, 2008 6:56 AM

GeneralRe: No demo project and no screenshotmemberDGDev14 Oct '08 - 0:59 
You'll receive a cross-thread exception. I can quickly make a method to set the owner though. Give me till tomorrow, I'll be adding more features and fixes.
 
.... EDIT ....
 
A quick edit to the demo and it works with ....
 
private void Form1_Layout(object sender, LayoutEventArgs e)
{
splash = SplashScreen.Current;
Activate();
splash.CloseSplashScreen();
}
 
I started the demo, open new explorer windows ... once it finished loading, the demo got focus.
Will upload the new files in a moment.
 
DGDev

Questionsyntax errormemberBob Mora13 Oct '08 - 15:23 
i get a syntax error in ShowForm(), using VS2005 / Framework 2.0
AnswerRe: syntax errormemberDGDev13 Oct '08 - 16:21 
Hmmm... try downloading the updated file and let me know if it continues. I need to quickly reinstall VS2005 before I can do testing on it.
 
DGDev

GeneralRe: syntax error [modified]memberBob Mora14 Oct '08 - 5:39 
I tried it at home (VS2008) and it worked fine. It is still the same in this PC with VS2005, line 147.
 
Edit: Ok I removed
 
{ IsBackground = true, Name = "SplashScreenThread" };
 
and it seems to work fine. Not sure what it does exactly, though.
 
modified on Tuesday, October 14, 2008 12:27 PM

GeneralRe: syntax errormemberDGDev14 Oct '08 - 11:06 
Hmm...
Your VS2005 isn't configured to use C# 3.0 which allows object initializers.
 
To fix your code for C# 2.0 use:
 
SplashScreenThread = new Thread(ShowForm);
SplashScreenThread.IsBackground = true;
SplashScreenThread.Name = "SplashScreenThread";
 
DGDev

GeneralRe: syntax errormembermaruf_d21 Oct '08 - 6:27 
To add to this, there are places where "var" is used in the demo code. Just replace it with the Class name on RHS and it should work.
GeneralRe: syntax errormemberDGDev23 Oct '08 - 10:54 
The updated files should now work on .NET 1.x - 3.5
I took replaced the "var"(s) which are only allowed in C#3.0+
 
DGDev

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

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 23 Oct 2008
Article Copyright 2008 by Anon1234567890
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid