#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

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

#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

#199 – An Application’s Windows Property Lists All of Its Windows

The Application class has a Windows property which is a collection of all of the windows that have been created by the current application.

Assume that we have an application with a main window that includes the following two buttons:

Whenever the user clicks on the Create New Window button, we create and show a new window.

    private void btnCreate_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        AnotherWindow win = new AnotherWindow();
        win.Title = DateTime.Now.ToLongTimeString();
        win.Show();
    }

In the Click event handler for the Where Are the Windows? button, we can iterate through all of the windows that the application created and display some information about each one.

        private void btnWhere_Click(object sender, RoutedEventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            foreach (Window w in App.Current.Windows)
            {
                sb.AppendFormat("Window [{0}] is at ({1},{2}).\n", w.Title, w.Top, w.Left);
            }

            MessageBox.Show(sb.ToString(), "My Windows");
        }

The final result: