Background:
I am working on a WPF application that uses the MEF framework to automatically link the necessary libraries and components for the app. With people adding their own components, the loading takes anywhere from 0-2 seconds to 6-7 seconds on slower machines. For this, I think a nice splash screen to let the user know the application is loading would be necessary. Ideally the splash screen would display an animated progress bar as well as a status text field describing which components are being loaded.
Problem:
I designed a splash screen window that is called right at the start of the application (OnStartup
), followed by the loading of the MEF bootstrapper. Problem is of course, the window does not animate because it is on the same thread as the MEF bootstrapper loading. I tried putting the bootstrapper on a separate thread but it complains that it is not an STA thread. Even on an STA thread it still didn't like it and it threw errors when trying to load the main app window. I can't put the splash screen window itself on a separate thread because then I don't have access to it, and it has to be an STA thread also because its a UI component. (Realized this is untrue, I can talk to the thread)
Update
I found a solution where I kept the splash screen window in a separate STA thread. Thank you everyone who replied for pointing me in the right direction:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Dispatcher threadDispacher = null;
Thread thread = new Thread((ThreadStart)delegate
{
threadDispacher = Dispatcher.CurrentDispatcher;
SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext(threadDispacher));
loadingWindow = new LoadingWindow();
loadingWindow.Closed += (s, ev) => threadDispacher.BeginInvokeShutdown(DispatcherPriority.Background);
loadingWindow.Show();
System.Windows.Threading.Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
var bootstrapper = new Bootstrapper();
bootstrapper.Run();
if (threadDispacher != null)
{
threadDispacher.BeginInvoke(new Action(delegate { loadingWindow.Close(); }));
}
}
Dispatcher
to marshal calls onto the UI thread of the window. – Graubert