The concept of a splash screen doesn\'t strike me as something that should be so complicated, but I\'m having trouble getting the whole splash screen painted.
Let\'s
Why not when you run the app open a form which loads whatever you need to load into a class, then when it's done loading, open your main form and send the class into it? Alternatively you can use a singleton to load everything.
In your Program.cs:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new SplashScreen());
}
Then in SplashScreen:
public SplashScreen()
{
InitializeComponent();
LoadEverything();
this.Visible = false;
MainForm mainForm = new MainForm(LoadedClass);
mainForm.ShowDialog();
this.Close();
}
I need to update this:
Here's working code (the above is just the concept).
public SplashScreen()
{
InitializeComponent();
_currentDispatcher = Dispatcher.CurrentDispatcher;
// This is just for the example - start a background method here to call
// the LoadMainForm rather than the timer elapsed
System.Timers.Timer loadTimer = new System.Timers.Timer(2000);
loadTimer.Elapsed += LoadTimerElapsed;
loadTimer.Start();
}
public void LoadMainForm()
{
// Do your loading here
MainForm mainForm = new MainForm();
Visible = false;
mainForm.ShowDialog();
System.Timers.Timer closeTimer = new System.Timers.Timer(200);
closeTimer.Elapsed += CloseTimerElapsed;
closeTimer.Start();
}
private Dispatcher _currentDispatcher;
private void CloseTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (sender is System.Timers.Timer && sender != null)
{
(sender as System.Timers.Timer).Stop();
(sender as System.Timers.Timer).Dispose();
}
_currentDispatcher.BeginInvoke(new Action(() => Close()));
}
private void LoadTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (sender is System.Timers.Timer && sender != null)
{
(sender as System.Timers.Timer).Stop();
(sender as System.Timers.Timer).Dispose();
}
_currentDispatcher.BeginInvoke(new Action(() => LoadMainForm()));
}
Try putting the call to loadAndCheckDatabase in a background thread, moving the close of the splash screen there, or simply closing it with a timer in the splash screen. With the work in a background thread, the all UI functions will be able to operate without interruption.
You can use the await command with .Net Framework 4.5 Your form will not be visible until the task is completed
private void YourForm_Load(object sender, EventArgs e)
{
//call SplashScreen form
SplashScreen splash = new SplashScreen();
splash.Show();
Application.DoEvents();
//Run your long task while splash screen is displayed i.e. loadAndCheckDatabase
Task processLongTask = loadAndCheckDatabase();
//wait for the task to be completed
processLongTask.Wait();
splash.Close();
//...
}
You are displaying the splash screen and checking your database on the same thread. The thread can only do one thing at a time.
A quick and cheap way to fix this is to have loadAndCheckDatabase()
call Application.DoEvents()
periodically. However that's a cheap fix.
You really want to run loadAndCheckDatabase() on its own thread, a BackgroundWorker is a nice simple way to do this.
Like me you probably created this as an afterthought and do not want to go through all the heck of redesigning your code to fit multi-threaded architecture...
First create a new Form called SpashScreen, in the properties click on BackgroundImage and import whatever image you want. Also set FormBorderStyle to None so that you can't click on the x to close the screen.
public Form1()
{
InitializeComponent();
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerAsync(); // start up your spashscreen thread
startMainForm(); // do all your time consuming stuff here
bw.CancelAsync(); // close your splashscreen thread
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
SplashScreen ss = new SplashScreen();
ss.Show();
while (!worker.CancellationPending) //just hangout and wait
{
Thread.Sleep(1000);
}
if (worker.CancellationPending)
{
ss.Close();
e.Cancel = true;
}
}
This does not support progress bar or any fancy stuff but I am sure it can be tweaked.
You should be running the splash screen in a different thread, that should allow it to draw properly.
Have a look here:
http://www.codeproject.com/KB/cs/prettygoodsplashscreen.aspx