#1,104 – How the Splash Screen Works

You can configure a splash screen in a WPF application by adding an image to the solution and setting its build action to SplashScreen.  The image will appear while the application is loading and then disappear as soon as the main window appears.

You can see how the splash screen works by looking at the code generated at build time for your main application class.  This will be in a file that looks something like App.g.cs.

To open the file, enable the Show All Files option and then look for App.g.cs under the obj directory.

1104-001

In the Main method, a SplashScreen instance is created and the name of the image is passed to its constructor.  It’s Show method is called and then the normal Application initialization is done. The Show method accepts a boolean indicating that the splash screen should be hidden once the main window is shown.

1104-002

 

Advertisement

#1,103 – Configuring a Splash Screen

A splash screen is a simple image that appears while your application is loading.  It typically goes away just prior to the appearance of the main application window.

To add a splash screen to your WPF application, you start by adding an image to your project.

1103-001

1103-002

1103-003

 

Once added to the project, select the image file in Solution Explorer.

1103-004

Set the Build Action for the file to SplashScreen.

1103-005

Build and run the application.  As the application starts, the splash screen image will automatically be shown.  It will disappear as soon as the main window of the application appears.

1103-006

 

#1,102 – Shutting Application Down after Handling Unhandled Exception

You can handle the DispatcherUnhandledException event in your main application object to intercept any unhandled exceptions that would otherwise crash your application.

You’ll typically handle DispatcherUnhandledException in order to handle unforeseen exceptions in a more friendly manner. After doing something with the exception information, e.g. logging it or notifying the user, you typically have the following options.

  • Ignore cause of exception and continue execution
    • Set e.Handled to true
  • Allow unhandled exception to crash application as it normally would
    • Leave e.Handled set to false
  • Shut down gracefully  (typical behavior)
    • Set e.Handled to true
    • Invoke Application.Shutdown()

You’ll most often select the third option.  If you’re logging or reporting exception information in a friendly manner, you will want to mark Handled as true.  And you do typically want to shut down and application after something unexpected happens.  Often you don’t know what state your application is in, so it’s desirable to just exit.

 

#1,101 – Defining a Handler for Unhandled Exceptions

When an exception gets thrown in a WPF application and not handled anywhere in the code, an unhandled exception occurs and the application is forced to exit.

You can handle exceptions that would otherwise be unhandled by handling theApplication.DispatcherUnhandledException event.  Below, we display a better error message and set the Handled property, to avoid shutting down the application.

This handler should be defined in the main application class (inherits from Application).

private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
    string friendlyMsg = string.Format("SO sorry that something went wrong.  The error was: [{0}]", e.Exception.Message);
    string caption = "Error";
    MessageBox.Show(friendlyMsg, caption, MessageBoxButton.OK, MessageBoxImage.Error);

    // Signal that we handled things--prevents Application from exiting
    e.Handled = true;
}

We wire up the handler by setting a value for DispatcherUnhandledException in XAML.

<Application x:Class="WpfApplication1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml"
             DispatcherUnhandledException="Application_DispatcherUnhandledException">
</Application>

#1,100 – OnExplicitShutdown Shutdown Mode

By default, a WPF application terminates when all of its windows are closed.  This corresponds to a value of OnLastWindowClose for the main Application object’s ShutdownMode property.

You can also set the ShutdownMode property to OnExplicitShutdown.  This indicates that the application will not terminate even after the user closes all of its windows.  Instead, you need to explicitly exit the application from within your code.

Below, we set ShutdownMode to OnExplicitShutdown.

<Application x:Class="WpfApplication1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml"
             ShutdownMode="OnExplicitShutdown">
    <Application.Resources>

    </Application.Resources>
</Application>

If you run this application and then close its main window, you’ll see the application disappear from the “Apps” section of Task Manager, but still show up under “Background processes”.

1100-001

Below is sample code that explicitly shuts down the application 10 seconds after the main window closes.

        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);

            // Shut things down 10 secs from now
            Timer t = new Timer(
                (state) => { App.Current.Shutdown(); }, 
                null, 10000, -1);
        }

 

#1,099 – OnMainWindowClose Shutdown Mode

By default, a WPF application terminates when all of its windows are closed.  This corresponds to a value of OnLastWindowClose for the main Application object’s ShutdownMode property.

You can also set the ShutdownMode property to OnMainWindowClose.  This indicates that the application should terminate when the main window closes.  Any other windows that are currently open will be automatically closed as the application terminates.

The application’s main window is the one specified using the Application object’s StartupUri property.  Note that the MainWindow property of the main Application object will refer to the instance of the window created based on the StartupUri.

Below, we set ShutdownMode to OnMainWindowClose.

<Application x:Class="WpfApplication1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml"
             ShutdownMode="OnMainWindowClose">
    <Application.Resources>

    </Application.Resources>
</Application>

After the application starts, we can create multiple child windows.

1099-001

At this point, if we close the main window, all three windows are closed and the application terminates.

#1,098 – OnLastWindowClose Shutdown Mode

By default, a WPF application terminates when all of its windows are closed.  This corresponds to a value of OnLastWindowClose for the main Application object’s ShutdownMode property.

We can see this in action if we have a main window and then instantiate a second window on a Button click.

        // Button in main window, opens another
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            OtherWindow ow = new OtherWindow();
            ow.Show();
        }

When we click on the button, the second window opens.

1098-001

At this point, we can close either window and the application will continue running.  It will only terminate when we close the second of the two open windows.  If we use the “Open Another” button to open multiple windows, the application will only terminate after we close the last open window.  The order that we close the windows doesn’t matter.

#1,097 – Getting Items in Context Menu to Correctly Use Command Binding

Let’s say that you set up command bindings for a main Window in an application and then use the command for some control (e.g. a Button) and also within a ContextMenu.  (Assume that the GreetUser_CanExecute method always returns true).

    <Window.CommandBindings>
        <CommandBinding Command="{x:Static loc:MainWindow.GreetUserCommand}"
                        CanExecute="GreetUser_CanExecute"
                        Executed="GreetUser_Executed"/>
    </Window.CommandBindings>

    <Window.ContextMenu>
        <ContextMenu>
            <MenuItem Command="{x:Static loc:MainWindow.GreetUserCommand}"/>
        </ContextMenu>
    </Window.ContextMenu>

    <StackPanel>
        <TextBox Name="txtSomeText"
                 Width="220" Height="25" Margin="10"/>
        <Button HorizontalAlignment="Center"
                Padding="10,5" Margin="10"
                Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}"
                Command="{x:Static loc:MainWindow.GreetUserCommand}"/>
    </StackPanel>

If you run this code and right-click on the window to bring up the context menu, the MenuItem is greyed out.  It’s not binding correctly to our CanExecute method.  The Button, on the other hand, did find the binding.

1097-001

The fix for this is to set the CommandTarget for the MenuItem to the PlacementTarget of the parent ContextMenu–the Window.  The MenuItem definition becomes:

            <MenuItem Command="{x:Static loc:MainWindow.GreetUserCommand}"
                      CommandTarget="{Binding Path=PlacementTarget, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}"/>

1097-002

 

#1,096 – The RoutedUICommand Adds a Text Property

When creating a custom command object, you can use either a RoutedCommand or a RoutedUICommand object.  Using the RoutedUICommand object allows you to associate some text with the command, using its Text property.  This text is typically the text that you want the user to see in the user interface.

Below, we create a new command and set its text.

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
        }

        public static RoutedCommand GreetUserCommand = new RoutedUICommand("Howdy!", "GreetUser", typeof(MainWindow));

        private void GreetUser_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        private void GreetUser_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            MessageBox.Show("Howdy howdy I'm a cowboy");
        }

        private void txtSomeText_PreviewExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            if (e.Command == ApplicationCommands.Paste)
            {
                e.Handled = true;
            }
        }
    }

In XAML, we reference the Text property for a button’s content. Note that we don’t need to specify text for the MenuItem–it will automatically get the text from the RoutedUICommand.

    <Window.CommandBindings>
        <CommandBinding Command="{x:Static loc:MainWindow.GreetUserCommand}" CanExecute="GreetUser_CanExecute" Executed="GreetUser_Executed"/>
    </Window.CommandBindings>

    <Window.ContextMenu>
        <ContextMenu>
            <MenuItem Command="{x:Static loc:MainWindow.GreetUserCommand}"/>
        </ContextMenu>
    </Window.ContextMenu>

    <StackPanel>
        <TextBox Name="txtSomeText" CommandManager.PreviewExecuted="txtSomeText_PreviewExecuted" Width="220" Height="25" Margin="10"/>
        <Button HorizontalAlignment="Center" Padding="10,5" Margin="10" Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}" Command="{x:Static loc:MainWindow.GreetUserCommand}"/>
    </StackPanel>

1096-001

#1,095 – Creating and Using a Custom Command

While WPF provides a number of predefined routed commands that you can use, it can also be useful to define your own command to use in your application.

We start by defining an instance of a RoutedCommand, in this case defined as a static member of our main Window class.  We also define code for the CanExecute and Executed events that will perform the logic that we bind the command to.

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
        }

        public static RoutedCommand GreetUserCommand = new RoutedCommand();

        private void GreetUser_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        private void GreetUser_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            MessageBox.Show("Howdy howdy I'm a cowboy");
        }
    }

We can now set up a command binding from XAML and set the Command property for controls that should execute our command.

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:loc="clr-namespace:WpfApplication1"
        Title="Commands" Width="320" Height="220">

    <Window.CommandBindings>
        <CommandBinding Command="{x:Static loc:MainWindow.GreetUserCommand}"
                        CanExecute="GreetUser_CanExecute"
                        Executed="GreetUser_Executed"/>
    </Window.CommandBindings>

    <Window.ContextMenu>
        <ContextMenu>
            <MenuItem Command="{x:Static loc:MainWindow.GreetUserCommand}"
                          Header="Say Howdy"/>
        </ContextMenu>
    </Window.ContextMenu>

    <StackPanel>
        <Button Content="Howdy" HorizontalAlignment="Center"
                Padding="10,5" Margin="10"
                Command="{x:Static loc:MainWindow.GreetUserCommand}"/>
    </StackPanel>
</Window>

We now have a command that executes when we click a button or a menu item in a context menu.

1095-001

1095-002