Displaying a WPF splash screen: a possible solution

Nov 16, 2010 at 6:44 PM
Edited Mar 9, 2012 at 8:30 AM

I am porting an existing WPF application to Caliburn.Micro and I need do display an animated splash screen while some background code is running (loading application add-ins, and compiling some scripts if needed). I know about the .NET 4.0 Splashcreen Class, but a static splash screen does not fit my needs, since I want to be able to inform the user about what the application is doing during initialization. The current application sets the splash screen as the application main window and replaces it with the real one during startup. Of course I could do the same this using CM, but I am looking for a method that fits nicely in the framework and is possibly reusable in other projects with zero effort.

Searching the forum I found just a couple of threads (this and this), but were quite inconclusive. I even checked the Caliburn forum, where I could find some insights regarding the issue, when using a static splashscreen, but nothing about a WPF/animated one.

I decided to try to code a solution, and I would appreciate some feedback from Rob and other interested people.

The main points of this approach are:

  • the WindowMainager hosts the code used to display the splash screen 
  • the WindowManager setups the splash screen view and the shell view, so that the latter is shown as soon as the former is closed
  • the shell view is not created until the splashscreen is about to close

In my opinion, displaying the main view after the splash screen is no different than deciding to display a sequence of windows where the second one is displayed when the first one is closed, that's why I decided to define a specialized interface for this purpose:

namespace SplashScreenTest
    #region Namespaces
    using Caliburn.Micro;


    /// <summary>
    ///   Interfcace used to define an extended window manager.
    /// </summary>
    public interface IWindowManagerEx : IWindowManager
        /// <summary>
        /// Shows a sequence of windows, waiting for the previous to be closed before displaying the next one.
        /// </summary>
        /// <param name="viewModels">The view models.</param>
        /// <param name="areDialogs">If set to <c>true</c>, the windows will be opened as dialog windows.</param>
        /// <param name="context">The context.</param>
        void ShowWindowSequence(object[] viewModels,
                                bool areDialogs = false,
                                object context = null);

Given such interface, displaying a splash screen on startup would just required to re-implement the bootstrapper DisplayRootView function

namespace SplashScreenTest
    /// <summary>
    /// Class used to define the application bootstrapper.
    /// </summary>
    public class Bootstrapper : Bootstrapper<Screen>
        /// <summary>
        ///   Displays the root view.
        /// </summary>
        protected override void DisplayRootView()
            var windowManager = IoC.Get<WindowManagerEx>();

            var splashScreenViewModel = IoC.Get<SplashScreenViewModel>();
            var shellViewModel = IoC.Get<ShellViewModel>();

            windowManager.ShowWindowSequence(new object[] { splashScreenViewModel, shellViewModel });

The code above will request the WindowManager to display the views associated to the view models in sequence, leaving such task to the manager implementation.

Achieving the required functionality can be tricky, since the default shutdown mode of a WPF application is to close the application as soon as every window is closed. The following implementation avoids the problem resetting the Application.Current.MainWindow before calling the close method, and displaying the next one (that becomes the MainWindow) before closing it:

        /// <summary>
        ///   Shows a sequence of windows defined by the specified view models.
        /// </summary>
        /// <param name = "viewModels">The view models.</param>
        /// <param name = "areDialogs">If set to <c>true</c>, the windows will be opened as dialog windows.</param>
        /// <param name = "context">The context.</param>
        /// <remarks>
        ///   Every window except the first is displayed as soon the next one is closed.
        /// </remarks>
        public void ShowWindowSequence(object[] viewModels, bool areDialogs = false, object context = null)
            //Get the first view model...
            object viewModel = viewModels.First();

            //Create the first window to display...
            Window window = CreateWindow(viewModel, false, context);

            //If the sequence contains more than a view model, prepare to show the next one...
            if (viewModels.Length > 1)
                //Attach an handler to the window loaded event to allow for the next window to be displayed...
                RoutedEventHandler loaded = null;
                loaded = (sender, args) =>
                    Window currentWindow = (Window)sender;
                    //Unregister the event, since it needs to be invoked once...
                    currentWindow.Loaded -= loaded;

                    //If the current window is the main one, closing it can provoke an application
                    //shutdown, so we need to remove the reference in the current application...
                    if (Application.Current.MainWindow == currentWindow)
                        Application.Current.MainWindow = null;

                    //Attach an handler to the closing event, so that we can display the next window...
                    CancelEventHandler closing = null;
                    closing = (s, e) =>
                        Window closingWindow = (Window)s;
                        closingWindow.Closing -= closing;

                        //Show the next window in the sequence...
                        object[] remainingViewModels = new object[viewModels.Length - 1];
                        Array.Copy(viewModels, 1, remainingViewModels, 0, remainingViewModels.Length);
                        ShowWindowSequence(remainingViewModels, areDialogs, context);
                    ((Window)sender).Closing += closing;

                window.Loaded += loaded;


This code cannot be just copy/pasted into a WindowManager derived control, since it requires the CreateWindow metod, which is private. This means that either the function is added to CM sources, or a new WindowManager is created from scratch (check here for more information about the issue).

The following project is a working sample of this approach, I would really appreaciate a review on this code and your thoughts regarding it.

Thanks in advance! :)


Edit: I noticed that changing the ShutdownMode is not needed, so I changed the project and the code accordingly.

Mar 9, 2012 at 7:20 AM

Did you get any further with this?
I too am looking for SplashScreen solution for CM that receives notifications from "background loading/initialisation"

Mar 9, 2012 at 8:31 AM
Edited Mar 9, 2012 at 8:33 AM

I am using this approach in a project of mine, and it seem to or fine.



The oly change is about the Bootstrapper: you need to override OnStartup and avoid to call the base.OnStartup method, calling the code in DisplayRootView instead.