How to run an animated SplashScreen at the same time as a Bootstrapper on STA threads
Asked Answered
P

1

6

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(); }));
        }
    }
Photoreceptor answered 25/7, 2013 at 14:40 Comment(2)
Why don't you have access to it if it's on a separate thread? You should still be able to reference it, you'll just have to guard your UI access and use the Dispatcher to marshal calls onto the UI thread of the window.Graubert
This won't work if the user chooses to close the splash screen. The application won't exit.Redletter
C
0

You were on the right way moving the bootstrapper to a thread of its own. What you should do, however is make sure that the portions that require being executed on the UI thread are also invoked on the UI thread.

So when the MEF bootstrapper is done, you can invoke the hiding of the splash window and opening of the main window on the main thread, even from the MEF's thread.

A way to get your message across to the main thread is by dispatcher

Clawson answered 25/7, 2013 at 14:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.