R
Reed Kimble
Guest
Adding a simple splash screen to an application to show the name, version, and other assembly information before the application loads is quite easy. You just add a new SplashScreen to the project and set the SplashScreen property using the dropdown on the Application Tab of the My Project screen.
However, if you want to customize the splash screen to include status text and/or a progress bar which provide feedback to the user while the application is loading it can be a bit more difficult.
The default behavior of a Windows Forms SplashScreen is to simply display itself for a few seconds prior to loading the application's main form. Because of this there is no opportunity to update any status or perform any application initialization while the splash screen is being displayed.
To get around these issues, we can create a small helper class (called "SplashManager" in this example) which will display the SplashScreen form on a secondary thread, allowing the main thread to execute your application initialization code and provide status feedback to the user.
To try this sample, please follow along with this walkthrough:
Step 1 - Create a new Windows Forms Application Project
Open Visual Studio (2008/2010/2012) and create a new Windows Application project. Perform this step as you would for any other Forms application you would create.
Step 2 - Add and Customize a SplashScreen
In the Solution Explorer, right click your project and select Add -> New Item. Choose a SplashScreen from the templates. In the SplashScreen designer window, modify the form to add a Label and a ProgressBar. An easy way to do this is to temporarily move the "Application Title" label to the left, then add a FlowLayoutPanel in the table cell where the Title label originally was. Set the background color of the FlowLayoutPanel to Transparent, then move the Title label back to the right into the Flow Layout Panel. Reduce the height of the Title label in the designer, then add your status Label and ProgressBar to the FlowLayoutPanel.
Now switch to code view for the SplashScreen and add two simple helper methods to the form:
Public Sub UpdateStatus(message As String)
StatusLabel.Text = message
End Sub
Public Sub UpdateProgress(value As Integer)
ProgressBar1.Value = value
End Sub
Be sure to use the same control names you used when adding the status Label and ProgressBar to the form in the designer.
Step 3 - Create the SplashManager Helper Class
Return to the Solution Explorer, right click your project and select Add -> New Item. Choose Class from the list of templates and name the class "SplashManager". Go to the code editor for the new SplashManager class and paste in the following code:
Public NotInheritable Class SplashManager
Private Shared _Splash As SplashScreen1
Private Shared _Wait As System.Threading.ManualResetEvent
Protected Sub New()
End Sub
Public Shared Sub ShowSplash()
If _Wait IsNot Nothing Then Exit Sub
_Wait = New System.Threading.ManualResetEvent(False)
System.Threading.Tasks.Task.Factory.StartNew(AddressOf DoShowSplash)
_Wait.WaitOne()
End Sub
Public Shared Sub CloseSplash()
If _Splash Is Nothing Then Exit Sub
_Splash.Invoke(New Action(AddressOf DoCloseSplash))
End Sub
Public Shared Sub UpdateStatus(message As String)
If _Splash Is Nothing Then Exit Sub
_Splash.Invoke(New Action(Of String)(AddressOf DoUpdateStatus), message)
End Sub
Public Shared Sub UpdateProgress(value As Integer)
If _Splash Is Nothing Then Exit Sub
_Splash.Invoke(New Action(Of Integer)(AddressOf DoUpdateProgress), value)
End Sub
Private Shared Sub DoShowSplash()
_Splash = New SplashScreen1
_Wait.Set()
_Splash.ShowDialog()
End Sub
Private Shared Sub DoCloseSplash()
_Splash.Close()
_Splash = Nothing
_Wait.Dispose()
_Wait = Nothing
End Sub
Private Shared Sub DoUpdateStatus(message As String)
_Splash.UpdateStatus(message)
End Sub
Private Shared Sub DoUpdateProgress(value As Integer)
_Splash.UpdateProgress(value)
End Sub
End Class
This simple class will expose methods to allow us to show the SplashScreen, wait for it to load, then provide us with methods to update the status and progress as well as close the SplashScreen when we are done. Be sure to use the name of the SplashScreen form you created in Step 2 when declaring the "_Splash" variable at the top of this code file.
When the ShowSplash() method is called, a new instance of the SplashScreen form will be created on a secondary thread and then shown. The methods to update status/progress and close the splash will invoke private helper methods to allow for cross-thread access of the SplashScreen from the main GUI form (which is running on the main thread).
Step 4 - Use an Application.Startup Event Handler to Show the Splash Screen
Return to the Solution Explorer and double click My Project. On the Application tab, click the "View Application Events" button at the bottom of the screen. In the ApplicationEvents code file which is generated, place your mouse within the "Partial Friend Class MyApplication" code block, then use the left dropdown at the top of the code editor window to select "(MyApplication Events)" and then the right dropdown to select "Startup". Place the single line of code "SplashManager.ShowSplash()" in the event handler stub generated by the editor. Your code file should then look like this:
Namespace My
' The following events are available for MyApplication:
'
' Startup: Raised when the application starts, before the startup form is created.
' Shutdown: Raised after all application forms are closed. This event is not raised if the application terminates abnormally.
' UnhandledException: Raised if the application encounters an unhandled exception.
' StartupNextInstance: Raised when launching a single-instance application and the application is already active.
' NetworkAvailabilityChanged: Raised when the network connection is connected or disconnected.
Partial Friend Class MyApplication
Private Sub MyApplication_Startup(sender As Object, e As Microsoft.VisualBasic.ApplicationServices.StartupEventArgs) Handles Me.Startup
SplashManager.ShowSplash()
End Sub
End Class
End Namespace
Step 5 - Code the Main Form's Load Event Handler to Initialize the Applicaiton and Provide Feedback
Now you can write the necessary logic required to initialize your application and get it ready for use. You can call the UpdateStatus and UpdateProgress methods of the SplashManager at various appropriate points through your initialization code.
In the following example, the form will update the splash screen's status and then put the main thread to sleep for two seconds to simulate some time-consuming initialization logic:
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
SplashManager.UpdateStatus("Loading application...")
System.Threading.Thread.Sleep(2000) 'simulate work
SplashManager.UpdateStatus("Load process 1...")
SplashManager.UpdateProgress(25)
System.Threading.Thread.Sleep(2000) 'simulate work
SplashManager.UpdateStatus("Load process 2...")
SplashManager.UpdateProgress(50)
System.Threading.Thread.Sleep(2000) 'simulate work
SplashManager.UpdateStatus("Load process 3...")
SplashManager.UpdateProgress(75)
System.Threading.Thread.Sleep(2000) 'simulate work
SplashManager.UpdateStatus("Load process 4...")
SplashManager.UpdateProgress(100)
System.Threading.Thread.Sleep(1000) 'allow user to see completed progress
SplashManager.CloseSplash()
End Sub
End Class
At this point you should be able to run the application and see the splash screen provide feedback while the main form loads.
Conclusion
By creating the splash screen on a secondary thread and using our own code to display it, we can show the splash when the application first launches and leave it up for as long as it takes to run all of the application's initialization logic. By using delegates to communicate between threads we can provide feedback to the user about the progress of the initialization process.
One important note is that the drawing of the colored band within the ProgressBar control relies on underlying Windows messages and it can be tricky to get the band to display the current progress if we do not display the SplashScreen form from the Application.Startup event handler.
But by following the above procedure it is fairly easy to create a long-running splash screen with feedback which will update its display properly.
(If anyone notes any major flaws with this design, please do reply to this thread with a detailed explanation.)
Reed Kimble - "When you do things right, people won't be sure you've done anything at all"
Continue reading...
However, if you want to customize the splash screen to include status text and/or a progress bar which provide feedback to the user while the application is loading it can be a bit more difficult.
The default behavior of a Windows Forms SplashScreen is to simply display itself for a few seconds prior to loading the application's main form. Because of this there is no opportunity to update any status or perform any application initialization while the splash screen is being displayed.
To get around these issues, we can create a small helper class (called "SplashManager" in this example) which will display the SplashScreen form on a secondary thread, allowing the main thread to execute your application initialization code and provide status feedback to the user.
To try this sample, please follow along with this walkthrough:
Step 1 - Create a new Windows Forms Application Project
Open Visual Studio (2008/2010/2012) and create a new Windows Application project. Perform this step as you would for any other Forms application you would create.
Step 2 - Add and Customize a SplashScreen
In the Solution Explorer, right click your project and select Add -> New Item. Choose a SplashScreen from the templates. In the SplashScreen designer window, modify the form to add a Label and a ProgressBar. An easy way to do this is to temporarily move the "Application Title" label to the left, then add a FlowLayoutPanel in the table cell where the Title label originally was. Set the background color of the FlowLayoutPanel to Transparent, then move the Title label back to the right into the Flow Layout Panel. Reduce the height of the Title label in the designer, then add your status Label and ProgressBar to the FlowLayoutPanel.
Now switch to code view for the SplashScreen and add two simple helper methods to the form:
Public Sub UpdateStatus(message As String)
StatusLabel.Text = message
End Sub
Public Sub UpdateProgress(value As Integer)
ProgressBar1.Value = value
End Sub
Be sure to use the same control names you used when adding the status Label and ProgressBar to the form in the designer.
Step 3 - Create the SplashManager Helper Class
Return to the Solution Explorer, right click your project and select Add -> New Item. Choose Class from the list of templates and name the class "SplashManager". Go to the code editor for the new SplashManager class and paste in the following code:
Public NotInheritable Class SplashManager
Private Shared _Splash As SplashScreen1
Private Shared _Wait As System.Threading.ManualResetEvent
Protected Sub New()
End Sub
Public Shared Sub ShowSplash()
If _Wait IsNot Nothing Then Exit Sub
_Wait = New System.Threading.ManualResetEvent(False)
System.Threading.Tasks.Task.Factory.StartNew(AddressOf DoShowSplash)
_Wait.WaitOne()
End Sub
Public Shared Sub CloseSplash()
If _Splash Is Nothing Then Exit Sub
_Splash.Invoke(New Action(AddressOf DoCloseSplash))
End Sub
Public Shared Sub UpdateStatus(message As String)
If _Splash Is Nothing Then Exit Sub
_Splash.Invoke(New Action(Of String)(AddressOf DoUpdateStatus), message)
End Sub
Public Shared Sub UpdateProgress(value As Integer)
If _Splash Is Nothing Then Exit Sub
_Splash.Invoke(New Action(Of Integer)(AddressOf DoUpdateProgress), value)
End Sub
Private Shared Sub DoShowSplash()
_Splash = New SplashScreen1
_Wait.Set()
_Splash.ShowDialog()
End Sub
Private Shared Sub DoCloseSplash()
_Splash.Close()
_Splash = Nothing
_Wait.Dispose()
_Wait = Nothing
End Sub
Private Shared Sub DoUpdateStatus(message As String)
_Splash.UpdateStatus(message)
End Sub
Private Shared Sub DoUpdateProgress(value As Integer)
_Splash.UpdateProgress(value)
End Sub
End Class
This simple class will expose methods to allow us to show the SplashScreen, wait for it to load, then provide us with methods to update the status and progress as well as close the SplashScreen when we are done. Be sure to use the name of the SplashScreen form you created in Step 2 when declaring the "_Splash" variable at the top of this code file.
When the ShowSplash() method is called, a new instance of the SplashScreen form will be created on a secondary thread and then shown. The methods to update status/progress and close the splash will invoke private helper methods to allow for cross-thread access of the SplashScreen from the main GUI form (which is running on the main thread).
Step 4 - Use an Application.Startup Event Handler to Show the Splash Screen
Return to the Solution Explorer and double click My Project. On the Application tab, click the "View Application Events" button at the bottom of the screen. In the ApplicationEvents code file which is generated, place your mouse within the "Partial Friend Class MyApplication" code block, then use the left dropdown at the top of the code editor window to select "(MyApplication Events)" and then the right dropdown to select "Startup". Place the single line of code "SplashManager.ShowSplash()" in the event handler stub generated by the editor. Your code file should then look like this:
Namespace My
' The following events are available for MyApplication:
'
' Startup: Raised when the application starts, before the startup form is created.
' Shutdown: Raised after all application forms are closed. This event is not raised if the application terminates abnormally.
' UnhandledException: Raised if the application encounters an unhandled exception.
' StartupNextInstance: Raised when launching a single-instance application and the application is already active.
' NetworkAvailabilityChanged: Raised when the network connection is connected or disconnected.
Partial Friend Class MyApplication
Private Sub MyApplication_Startup(sender As Object, e As Microsoft.VisualBasic.ApplicationServices.StartupEventArgs) Handles Me.Startup
SplashManager.ShowSplash()
End Sub
End Class
End Namespace
Step 5 - Code the Main Form's Load Event Handler to Initialize the Applicaiton and Provide Feedback
Now you can write the necessary logic required to initialize your application and get it ready for use. You can call the UpdateStatus and UpdateProgress methods of the SplashManager at various appropriate points through your initialization code.
In the following example, the form will update the splash screen's status and then put the main thread to sleep for two seconds to simulate some time-consuming initialization logic:
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
SplashManager.UpdateStatus("Loading application...")
System.Threading.Thread.Sleep(2000) 'simulate work
SplashManager.UpdateStatus("Load process 1...")
SplashManager.UpdateProgress(25)
System.Threading.Thread.Sleep(2000) 'simulate work
SplashManager.UpdateStatus("Load process 2...")
SplashManager.UpdateProgress(50)
System.Threading.Thread.Sleep(2000) 'simulate work
SplashManager.UpdateStatus("Load process 3...")
SplashManager.UpdateProgress(75)
System.Threading.Thread.Sleep(2000) 'simulate work
SplashManager.UpdateStatus("Load process 4...")
SplashManager.UpdateProgress(100)
System.Threading.Thread.Sleep(1000) 'allow user to see completed progress
SplashManager.CloseSplash()
End Sub
End Class
At this point you should be able to run the application and see the splash screen provide feedback while the main form loads.
Conclusion
By creating the splash screen on a secondary thread and using our own code to display it, we can show the splash when the application first launches and leave it up for as long as it takes to run all of the application's initialization logic. By using delegates to communicate between threads we can provide feedback to the user about the progress of the initialization process.
One important note is that the drawing of the colored band within the ProgressBar control relies on underlying Windows messages and it can be tricky to get the band to display the current progress if we do not display the SplashScreen form from the Application.Startup event handler.
But by following the above procedure it is fairly easy to create a long-running splash screen with feedback which will update its display properly.
(If anyone notes any major flaws with this design, please do reply to this thread with a detailed explanation.)
Reed Kimble - "When you do things right, people won't be sure you've done anything at all"
Continue reading...