#1,105 – Using Application’s Windows Collection to Interact with Other Windows

You can use the Application object’s Windows property to get a list of all active windows.  If you then cast to your specific subclass of Window, you can interact with the various child windows.

Suppose that we have a main window with a button for creating other windows.

        private void btnCreate_Click(object sender, RoutedEventArgs e)
        {
            OtherWindow ow = new OtherWindow();
            ow.Show();
        }

Assume that the child windows have a TextBox that binds to a property in the code-behind.

        <TextBox Text="{Binding SomeText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                 Margin="10" Height="25"/>

The code-behind would look like this:

    public partial class OtherWindow : Window, INotifyPropertyChanged
    {
        public OtherWindow()
        {
            InitializeComponent();
            this.DataContext = this;
        }

        private string someText;
        public string SomeText
        {
            get { return someText; }
            set
            {
                someText = value;
                RaisePropChanged("SomeText");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        private void RaisePropChanged(string prop)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
    }

We can now get information on all child windows as shown below (this is an event handler for another button on the main window).

        private void btnList_Click(object sender, RoutedEventArgs e)
        {
            StringBuilder sb = new StringBuilder();

            foreach (Window w in Application.Current.Windows)
            {
                OtherWindow ow = w as OtherWindow;
                if (ow != null)
                    sb.AppendLine(ow.SomeText);
            }

            MessageBox.Show(sb.ToString());
        }

1105-001

Advertisement

#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.

#759 – Device-Independent Units (DIPs)

(Also known as WPF Units)

In WPF, when you’re specifying size or position for user interface elements, the values are always by default in Device-Indepdent Units (DIPs).

1 DIP = 1/96 inch.  This means at 96 dpi, 1 DIP = 1 pixel.

At 120 dpi, 1 DIP = 1.25 pixels.  (120/96)

The purpose of using DIPs when indicating desired size or position is that controls will still have the same physical size on your screen, regardless of the DPI setting.  A button that is specified as being 96 DIPs wide will be 1″ wide, whether your display is set to 96 DPI, 120 DPI, or 150 DPI.

To convert from DIPs to pixels, you need to know your screen DPI setting (e.g. 96, 120):

# pixels = (DIPs) * (DPI / 96)

So 96 DIPs = 96 pixels at 96 DPI, and 96 DIPs = 120 pixels at 120 DPI.

#612 – Application Event Sequence for Page-Based Applications

When you create a page-based application in WPF, you use a NavigationWindow as the main window, which in turn hosts one or more Page objects.  (If you set the StartupUri property of the Application to point to a Page, a NavigationWindow will be created automatically).

The sequence of Application events that fire for a page-based application are listed below.

When you start the application (assuming that a Page is specified as the StartupUri):

  • Startup
  • Navigating
  • Navigated
  • LoadCompleted
  • Activated

When you shut the application down normally:

  • Deactivated
  • Exit

When you navigate to a new Page:

  • Navigating
  • NavigationProgress  (1 or more times)
  • Navigated
  • LoadCompleted

User is logging out of or shutting down Windows:

  • Deactivated
  • SessionEnding

Application gains focus:

  • Activated

Application loses focus:

  • Deactivated

#611 – Set Application Exit Code in Exit Event Handler

If you’re running applications from the command line in Windows, you can return an exit code from the application and use it to indicate whether the application was successful at doing whatever it was supposed to do.  Traditionally, an exit code of 0 indicates that the application completed successfully and positive values indicate errors.

To set a WPF application’s exit code, set the ApplicationExitCode property of the ExitEventArgs object in the application’s Exit event.

        private void Application_Exit(object sender, ExitEventArgs e)
        {
            // Assume we have a boolean variable indicating whether the
            //   application did its work successfully

            // Use 0 to indicate success, 1 to indicate that something went wrong
            e.ApplicationExitCode = (everythingWorkedOk) ? 0 : 1;
        }

You could then check this code in a .bat file:

WpfApplication11.exe

REM This evaluates to true if exit code was >= 1
if errorlevel 1 (
    echo Failure
) else (
    echo Success !
)

echo Actual exit code was %errorlevel%

#610 – Application Event Sequence

The sequence of events for an application’s main Application object that are fired are as follows (all events listed in the order that they fire):

When you start the application:

  • Startup
  • Activated

When you shut the application down normally (i.e. close main window):

  • Deactivated
  • Exit

If the application experiences an unhandled exception:

  • DispatcherUnhandledException

If user is logging out of or shutting down Windows:

  • Deactivated
  • SessionEnding

Application gets focus:

  • Activated

Application loses focus:

  • Deactivated