Skip to content

WPF Application

Gary edited this page Feb 26, 2015 · 2 revisions

Table of Contents

This section discusses WPF application structure. WinForms and WPF applications use ATF in similar ways. For information on similarities between WinForms and WPF, see Parallels in WPF and WinForms Support. For details on comparing and contrasting WinForms and WPF applications, see Converting from WinForms to WPF.

For an example of a WPF ATF application, see the ATF Simple DOM Editor WPF Sample. For a WinForms application that is very similar to this WPF sample and helps clarify the similarities and differences between the two, see the ATF Simple DOM Editor Sample.

App XAML

At a bare minimum, to display a window using ATF and WPF, you can create a WPF application project, add references to Atf.Core.dll, Atf.Gui.Wpf.dll, and System.ComponentModel.Composition. Then include the following for App.xaml, which is the XAML file in which the WPF application is set up:

<atf:AtfApp x:Class="WpfApp.App"
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:atf="http://www.sce.net/Atf.Gui.Wpf">
</atf:AtfApp>

This partially defines the class WpfApp.App. The rest of the WpfApp.App class definition is in the code behind file App.xaml.cs, which derives App from Sce.Atf.Gui.Wpf.Applications.AtfApp. For more about this class, see AtfApp Class.

App.xaml.cs handles all the other initialization for you, and provides a MainFormAdapter, which is a System.Window with some decoration to allow interoperation with ATF's WinForms components. App.xaml.cs also handles all the MEF composition, as discussed in MEF Setup.

Here is a minimal App.xaml.cs:

using System.ComponentModel.Composition.Hosting;
using Sce.Atf.Wpf.Applications;
using Sce.Atf.Wpf.Controls;
using Sce.Atf.Wpf.Interop;
using Sce.Atf.Wpf.Models;

namespace WpfApp
{
    public partial class App : AtfApp
    {
        /// <summary>
        /// Gets MEF AggregateCatalog for application</summary>
        protected override AggregateCatalog GetCatalog()
        {
            var typeCatalog = new TypeCatalog(
                typeof(MainWindow)             // Application's main window
                );

            return new AggregateCatalog(typeCatalog, StandardInteropParts.Catalog, StandardViewModels.Catalog);
        }
    }
}

This is all the code necessary to display a simple empty window. From this start, you can build up the rest of the application. For example, you can add more MEF components.

AtfApp Class

The AtfApp class is the base ATF WPF application class and derives from System.Windows.Application. You should derive WPF applications from this class to avoid rewriting common code. AtfApp implements IComposer, which is an interface for ComposablePart and CompositionContainer used for WPF applications with MEF.

AtfApp's constructor performs some of the same set up functions as the WinForms Main() function discussed in Initial Setup:

public AtfApp()
{
    // Setup thread name and culture
    Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.CurrentCulture;
    Thread.CurrentThread.Name = "Main";

    // Ensure the current culture passed into bindings is the OS culture.
    // By default, WPF uses en-US as the culture, regardless of the system settings.
    FrameworkElement.LanguageProperty.OverrideMetadata(
        typeof(FrameworkElement), new FrameworkPropertyMetadata(
            XmlLanguage.GetLanguage(System.Globalization.CultureInfo.CurrentCulture.IetfLanguageTag)));
}

Much of AtfApp is dedicated to composing components with MEF, which is discussed next in MEF Setup.

MEF Setup

If a WPF application uses MEF, it needs to specify the components it uses. This section discusses a way to do this using AtfApp.

AtfApp has an OnStartup() method that is called when a WPF application starts up:

protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);

    if (Compose())
    {
        OnCompositionBeginning();

        foreach (var initializable in m_initializables)
            initializable.Value.Initialize();

        OnCompositionComplete();

        m_mainWindow.ShowMainWindow();
    }
    else
    {
        Shutdown();
    }
}

OnStartup() calls the Compose() method to compose the MEF components. In turn, Compose() calls the abstract method GetCatalog(), which actually sets up the MEF catalog. OnStartup() also initializes all the MEF components using the ATF IInitializable.Initialize() method.

The ATF application should provide a GetCatalog() implementation that sets up the MEF catalog. Here's how the ATF Simple DOM Editor WPF Sample does it in App.xaml.cs, defined in the partial class App:

public partial class App : AtfApp
{
	/// <summary>
	/// Gets MEF AggregateCatalog for application</summary>
	protected override AggregateCatalog GetCatalog()
	{
		var typeCatalog = new TypeCatalog(
			typeof(ControlHostService),             // Docking framework
			typeof(MainWindow),                     // Application's main window
			...
			typeof(BasicPythonService),             // Scripting service for automated tests
			typeof(AtfScriptVariables),             // Exposes common ATF services as script variables
			typeof(AutomationService)               // Provides facilities to run an automated script using the .NET remoting service

			);

		return new AggregateCatalog(typeCatalog, StandardInteropParts.Catalog, StandardViewModels.Catalog);
	}
	...
}

The GetCatalog() method returns an AggregateCatalog, which contains the TypeCatalog with the components the sample application uses — as well as a couple of ComposablePartCatalog objects containing WPF versions of ATF components that are generally useful for WPF applications: StandardInteropParts.Catalog and StandardViewModels.Catalog. For more information on StandardInteropParts, see Using WinForms Controls in WPF.

Application Exit

AtfApp also provides a OnExit() called when the WPF application exits. OnExit() disposes of MEF components' resources. You can override it to perform additional clean up. Here is the base method:

protected override void OnExit(ExitEventArgs e)
{
    base.OnExit(e);

    foreach (var disposable in m_disposables)
    {
        disposable.Value.Dispose();
    }

    if (Container != null)
    {
        Container.Dispose();
    }
}

Topics in this section

Clone this wiki locally