Implementing a Splash Screen With WPF Dependency Injection

Implementing a Splash Screen With WPF Dependency Injection

Earlier in the Year I did two posts on Dependency Injection and Splash Screen (Pop-Ups).

  • https://catiawidgets.net/2023/06/17/c-setting-up-wpf-with-dependency-injection/
  • https://catiawidgets.net/2023/10/17/c-popup-ui-base-class/

I want to show how to bring these two together.

App.xaml

Just like we did in the previous post we want to change StartUpURI to StartUp and point it to the OnStartup Class in the App.xaml.cs file.

<Application x:Class="TrueNorth.Desktop.WPF.MainClient.UI.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:TrueNorth.Desktop.WPF.MainClient.UI"
             Startup="OnStartup">
    <Application.Resources>
         
    </Application.Resources>
</Application>

App.xaml.cs


Within the App.xaml.cs file we can add the OnStartUp method and establish the dependency injection pattern as shown below. There are four key steps.

  1. Creating private splashscreen member.
  2. Adding the splash screen to the services as a singleton.
  3. Retrieving the hosted splash screen service.
  4. Finally calling the windows Show() method to display the splash screen window.
private SplashScreenWindow? _splashScreenWindow;

services.AddSingleton(n => new SplashScreenWindow(_mainwindow));

_splashScreenWindow = _host.Services.GetRequiredService<SplashScreenWindow>();

_splashScreenWindow.Show();
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using Serilog;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Windows;

using TrueNorth.Desktop.WPF.MainClient.UI.SplashScreen;

namespace TrueNorth.Desktop.WPF.MainClient.UI
{
    public partial class App : Application
    {
        private SplashScreenWindow? _splashScreenWindow;
        private MainWindow? _mainwindow;
        private ILogger? _logger;
        private IHost? _host;

        public App() { }

        private void OnStartup(object sender, StartupEventArgs e)
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

            IConfigurationBuilder builder = new ConfigurationBuilder();
            BuildConfig(builder);

            _logger = new LoggerConfiguration()
                .ReadFrom.Configuration(builder.Build())
                .Enrich.FromLogContext()
                .CreateLogger();

            _logger.Information("App - OnStartup - Application Starting");
            _logger.Information("App - OnStartup - Adding Dependancies");

            _host = Host.CreateDefaultBuilder()
                .ConfigureServices((context, services) =>
                {
                    services.AddSingleton(m => new MainWindow());
                    services.AddSingleton(n => new SplashScreenWindow(_mainwindow));
                    services.AddSingleton(_logger);
  
                    services.AddSingleton(o => new HttpClient(new SocketsHttpHandler()
                    {
                        PooledConnectionLifetime = TimeSpan.FromMinutes(1)
                    }
                )
                    {
                        BaseAddress = new Uri("https://truenorthplmuiadminazurefunctions.azurewebsites.net/api/v1/")
                    });
                })
                .UseSerilog()
                .Build();

            _logger.Information("App - OnStartup - Set Initial View Model.");
            //_navigationStore.CurrentViewModel = _host.Services.GetRequiredService<IConfigFileBuilderViewModel>();

            _logger.Information("App - OnStartup - Creating the Main UI.");
            _mainwindow = _host.Services.GetRequiredService<MainWindow>();

            _logger.Information("App - OnStartup - Creating the SplashScreen UI.");
            _splashScreenWindow = _host.Services.GetRequiredService<SplashScreenWindow>();

            _logger.Information("App - OnStartup - Setting the UI DataContext.");
            //_mainwindow.DataContext = ActivatorUtilities.CreateInstance<MainViewModel>(_host.Services);

            _logger.Information("App - OnStartup - Showing UI.");
            _splashScreenWindow.Show();
        }
        private static void BuildConfig(IConfigurationBuilder builder)
        {
            builder.SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
                .AddEnvironmentVariables();
        }
    }
}

Splash Screen XAML

I have created a very simple splash screen similar to the one in the previous post.

<Window x:Class="TrueNorth.Desktop.WPF.MainClient.UI.SplashScreen.SplashScreenWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TrueNorth.Desktop.WPF.MainClient.UI.SplashScreen"
        xmlns:CustomSplash="clr-namespace:TrueNorth.Desktop.WPF.UserControls.SplashScreenLib.MainUI;assembly=TrueNorth.Desktop.WPF.UserControls.SplashScreenLib"
        mc:Ignorable="d"
        Title="SplashScreenWindow"
        WindowStartupLocation="CenterScreen"
        WindowStyle="None"
        Topmost="True"
        AllowsTransparency="True" 
        Background="Transparent" 
        ResizeMode="NoResize"
        ShowInTaskbar="True"
        Height="350" Width="600"
        MouseDown="Window_MouseDown">

    <CustomSplash:SplashScreen
        ucBackGroundImage="Assets/Images/TrueNorth.png"
        ucBackgroundColor="Black"
        ucTitleText="Importing Required Assets"
        ucTitleFontFamily="latin"
        ucTitleFontWeight="DemiBold"
        ucTitleFontHeight="20"
        ucBorderRadius="25"
        ucImageHeight="250"
        ucImageWidth="600"
        ucTextMargin="0 20 0 20"
        ucProgressWidth="400"
        ucProgressHeight="8"/>
</Window>

Splash Screen XAML.cs

Below is the code behind that utilizes the ‘ISplashPopup’ implementation created in the previous post.

 public partial class SplashScreenWindow : Window
 {
     private readonly ISplashPopup _splashScreen;
     public SplashScreenWindow(Window mainWindow)
     {
         InitializeComponent();
         _splashScreen = new SplashPopup(mainWindow);
         _splashScreen.parentWindow = this;
         _splashScreen.Show();
     }
     private void Window_MouseDown(object sender, MouseButtonEventArgs e)
     {
         try
         {
             this.DragMove();
         }
         catch { }
     }
 }

I’m sure that there are other ways in which to do this but this is the way that works for me.