devxlogo

Managing Your WPF Splash Screen’s Lifecycle

Managing Your WPF Splash Screen’s Lifecycle

splash screen is created upon application startup and is ended after the the main Window class’s initialization code executes. Professional-looking applications geenrally use splash screens to let their users know where the application is in the initiliazation process. This generic splash screen is different from the SplashScreen class provided by Microsoft (.NET Framework 3.5 SP1), which displays only an image file and only in the center of the screen.

Sometimes, adding splash screens can be problematic. For instance, suppose you’ve added a WPF window to your project and spiced it up with some animation effects, which you implemented directly in XAML. Then, you specified the Startup event handler in the app.xaml file, like this:

	

In the App class, you added a property:

private static Thread threadSpashScreen;public static Thread ThreadSpashScreen(){	get { return app.threadSpashScreen };}

You also added code for two methods as follows:

private void Application_Startup(object sender, StartuoEventArgs e){	threadSpashScreen = new Thread(ExecuteSplashScreen);	threadSplashScreen.SetAppartmentState(AppartmentState.STA);	. . .threadSplashScreen.Start();}private void ExecuteSplashScreen(){	YourSplashScreen splScr = new YourSplashScreen();	. . .	splScr.ShowDialog();   //Modal dialog box}

At the end of the main Window class?s initialization code, you’ve called Abort():

	App.ThreadSplashScreen.Abort();

This works without any visible problems. Or so you think.

So What?s the Problem?
Now suppose that one day, you’re troubleshooting an exception in the application code and you enable the Managed Debugging Assistants (MDA) in the VS 2008 debugger. (For those following along at home, go to the Exceptions Dialog Box in the DebugExceptions?menu item.)

You start the application and as the splash screen started to disappear, a dialog boxappears with the following error message:

AsynchronousThreadAbort was detected"User code running on thread 5756 has attempted to abort thread 5404. If the thread being aborted was in the middle of an operation that modifies a global state or uses native resources, this error could indicate a corrupt state or resource leak. Aborting threads other than the currently running thread is strongly discouraged." 

The source of this problem is how you’ve managed the lifecycle of the splash screen.

The Solution
It’s clear that the error message was triggered by the AsynchronousThreadAbort MDA along with CLR; at the moment your code attempted to asynchronously call Abort() from the main thread to another, worker thread that executed ExecuteSplashScreen().

Note that this dialog box has a variation: Its appearance depends on whether you’ve checked a box in the project’s properties. In Properties, go to the Debug tab. Is “Enable unmanaged code debugging” checked? When this box is checked, it changes your dialog box;s title to “Microsoft Visual Studio” and shows two buttons: “Break” and “Continue.” On a 64-bit machine, you cannot do mixed mode debugging.

To fix this, you could add a try-catch statement to the ExecuteSplashScreen() method and include all its code in the try block. But when you run the application again and close the MDA’s dialog box, it throws another exception:

Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack.

So, it does not matter whether you include the try-catch statement or not. Including the try-catch statement ends the thread because its function ends. Without the try-catch statement, the thread terminates because it cannot continue execution after an unhandled exception.

In this particular case, even though the thread terminates at an unsafe checkpoint at an unpredictable moment, it doesn’t cause problems. The goal of the Abort() call is to end the thread that’s done its work and is no longer needed by the application. Though it’s against good practice to unintentionally use exceptions for “normal” execution path, in this example there is no consensus on terminating the thread with the ThreadAbortException exception.

Alternative Solutions

  • MSDN suggests using a common property that signals the target thread and requests an interrupt. The target thread then checks for requests in safe checkpoints and ends gracefully.
  • You could add an invisible button to the splash screen and initiate a Click event that closes the splash screen window. The following XAML example shows mix of code with markup:
              . . .                           . . .                          

    Instead of calling Abort(), this code simulates a click event for the button by using classes from the WPF UI Automation namespace. The following code snippet shows how:

    AutomationElement applWindow = AutomationElement.RootElement.FindFirst(	TreeScope.Children,  new PropertyCondition(                    AutomationElement.AutomationProperty, ?myName?);AutomationElement btn = applWindow.FindFirst(	TreeScope.Descendants,  new PropertyCondition(                    		AutomationElement.NameProperty, ?buttonClick?);InvokePattern btnInvokePattern = btn.GetCurrentPattern                    (InvokePattern.Pattern) as InvokePattern;btnInvokePattern.Invoke();

    Of course, you’ll need references to UIAutomationClient and UIAutomationTypes, which you can obtain from their corresponding DLLs located under c:Program FilesReference AssembliesMicrosoftFrameworkv.3.0.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist