- Community Pick
- Experts Exchange Approved
The "Splash Screen" Setting in Project Properties:
What isn't commonly found, though, are good examples of how to update the splash screen with progress information from the main form as it loads. Many examples and tutorials simply use a static splash screen and leave it at that. MSDN provides an example of how to "update the splash screen with status information" in the MSDN documentation of: My.Application.SplashScr
In that example, the code is being run from the Application.Startup() event, and changes to the splash screen are done in a direct manner:
Careful! Multi-threading ahead...
The code is misleading because it implies that we can do this from anywhere. What isn't well documented or being made clear is that the splash screen and the main form of an application actually run in two different threads. Attempts to use similar code from the Load() event of your main form will result in varying degrees of success depending upon your version of Visual Studio. The code does demonstrate that "My.Application.SplashScre
Since the splash screen and the main form are in two different threads, the correct approach to communicating between them is to use the Invoke() method with a delegate. This is covered in the MSDN article, How to: Make Thread-Safe Calls to Windows Forms Controls.
Many don't even think to use this approach, though, since cross-thread communication is not normally an issue when dealing with two forms. The splash screen, then, is an exception to the rule!
The pattern outlined in the article above is as follows:
We use InvokeRequired() to determine if the calling thread is different from the thread that created the control. If yes, then we create an instance of the delegate that points to the same exact method. Next we use Invoke() to run the delegate on the thread that created the control and pass the parameters using an array of Object. This actually results in a recursive call since the delegate points to the same method. On the second run InvokeRequired() will return false and the Else block will execute where the control can be safely updated.
So let's apply the same pattern to a splash screen. Below is a simple setup consisting of a Borderless Form with a BackgroundImage, Label and a ProgressBar:
Here is the code for frmSplashScreen:
Note that I'm using "Me" instead of a control name to check for InvokeRequired(). The "Me" in this case represents the Form itself and is valid since Forms also Inherit from Control. All controls run in the same thread as the form that contains them so this is a clean and safe method of checking. Also note that in the Else block I am updating both the Label and the ProgressBar at the same time. You don't need a separate method with an accompanying delegate for every control; just check against the form and update all controls at once. The delegate being used receives both parameters and the Object array contains both parameters passed to the method.
With that code in place, all the main form has to do is call the UpdateProgress() method and the splash screen will take care of the rest. Remember, a reference to the splash screen instance can be obtained with "My.Application.SplashScre
The Splash Screen in Action!
This article hasn't really introduced anything new or mind blowing...it just puts two and two together to accomplish something that really should be much simpler!
by: MrFantastic6 on 2010-10-18 at 17:21:40ID: 20604