Skip to content

Using ATF Components

Gary edited this page Jan 29, 2015 · 10 revisions



Table of Contents

This section discusses what you need to do to use ATF components. What's needed varies from component to component, and this section provides guidelines on finding what you need to do to use a component.

Add Components to Catalog

As shown in Creating a Catalog, you add the components you want to a MEF TypeCatalog in your Main() function. You don’t need to instantiate or directly access component classes.

You also need to add using statements for the namespaces of whatever components you use, or fully qualify the component names in the catalog.

For guidance in choosing components, see Important ATF Components and Finding ATF Components.

Set Up MEF Infrastructure

The section MEF Composition shows how most ATF samples provide the code that MEF requires. You can adapt this to your own application. To see how the ATF Simple DOM Editor Sample does it, (link to the sample source).

Note that if you are using any component that requires initialization that its constructor can't do, you must call the InitializeAll() extension method of CompositionContainer, as seen in these lines from Program.cs of ATF Simple DOM Editor Sample; most samples that use MEF have code like this (link to source):

// Initialize components that require it. Initialization often can't be done in the constructor,
//  or even after imports have been satisfied by MEF, since we allow circular dependencies between
//  components, via the System.Lazy class. IInitializable allows components to defer some operations
//  until all MEF composition has been completed.
container.InitializeAll();

Even if none of the components you use requires initialization, making this call does no harm, so your application should probably always do it—in case you add a component that needs initialization or a component changes to require initialization.

Satisfy Component Requirements

Most components are not self-contained and require something additional to work properly.

For some components, you need to do very little: the main thing you do is add the component to your MEF catalog. For instance, the StandardFileExitCommand component adds the File > Exit menu item that exits the application, and it requires no additional code in the application to do this.

However, StandardFileExitCommand does require the CommandService component, which handles commands in menus and toolbars. If you include StandardFileExitCommand but leave CommandService out of your MEF catalog, the File > Exit menu item does not appear. In fact, your application would have no menus at all (unless you added them some other way). If a component requires other components in order to function properly, this is sometimes noted in the component's source.

Other components require the application to provide some functionality. For example, the StandardFileCommands component adds standard File menu commands for New, Open, Save, SaveAs, and Close. The application, in turn, must provide its own code (possibly in a component) to handle these file commands: processing opened file data, displaying it, and so on. In other words, the application performs its own specialized functions for each menu command. How to add these functions is discussed in the next section.

Discovering What's Required

To see what is needed by a component to function, look at its [Import] attributes. Typically an interface is imported, though components are also imported. For information on what's required for some components, see Details on Using Selected ATF Components.

If any ATF samples use a component, any other components needed by that component are also listed in the sample's MEF TypeCatalog.

An import can be satisfied in two ways:

  • Import a component that exports the interface.
  • Implement the interface in the application, which can be done in a component the application supplies. You do this when there is no component that exports the interface, or you need to implement the interface differently.
As mentioned, a component may require other components or require some functionality from the application itself.

Functionality Required From Other Components

To illustrate with an example, determine what StandardFileExitCommand needs by looking at its [Import] attributes. StandardFileExitCommand.cs contains three [Import] attributes (link to source1 and link to source2):

[ImportingConstructor]
public StandardFileExitCommand(ICommandService commandService)
...
[Import(AllowDefault = true)]
private IMainWindow m_mainWindow;

[Import(AllowDefault = true)]
private Form m_mainForm;

The latter two imports are common in components that work with a UI: a System.Windows.Forms.Form for a WinForm application, and a Sce.Atf.Applications.IMainWindow. IMainWindow abstracts the idea of a main window for the application and allows components to work with WinForms, WPF, and other UI toolkits. The Main() function in Program.cs creates a MainForm (derived from Form), which satisfies these two import requirements.

In the first import, decorated with [ImportingConstructor], the parameter for the StandardFileExitCommand constructor indicates the component imports ICommandService. In turn, the ATF component CommandService exports ICommandService (link to source):

[Export(typeof(ICommandService))]
[Export(typeof(IInitializable))]
[Export(typeof(CommandService))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class CommandService : CommandServiceBase

Therefore, adding the CommandService component satisfies StandardFileExitCommand's need for a ICommandService, so CommandService should be included in the MEF catalog whenever StandardFileExitCommand is.

Note that you could also satisfy this import by creating and adding your own component that exports ICommandService.

Functionality Required From the Application

Now consider the StandardFileCommands component, which adds standard File menu commands. It stands to reason that this component would require support from the application, since these commands are clearly application-dependent. What exactly is required?

Here are StandardFileCommands's imports (link to source1 and link to source2):

[ImportingConstructor]
public StandardFileCommands(
    ICommandService commandService,
    IDocumentRegistry documentRegistry,
    IFileDialogService fileDialogService)
...
[Import(AllowDefault = true)]
private IStatusService m_statusService;

[ImportMany]
private Lazy<IDocumentClient>[] m_documentClients;

The constructor associated with the [ImportingConstructor] has three parameters. This import is very similar to the one for StandardFileExitCommand. It indicates components are required that export ICommandService, IDocumentRegistry, and IFileDialogService. These exports can be supplied by the ATF components CommandService, DocumentRegistry, and FileDialogService.

Similarly, the second import indicates that a component supplying IStatusService is needed, which is exported by the ATF component StatusService.

The last import indicates something the application itself must supply: something that exports IDocumentClient. This makes sense, because the IDocumentClient interface contains methods to support File commands, such as CanOpen() and Open() for the Open command (link to IDocumentClient source).

There are two other things to note about the IDocumentClient import:

  • An array is imported into and the attribute [ImportMany] is used. This allows an application to provide several implementations of IDocumentClient in case it handles multiple document types.
  • It uses Lazy<T> for lazy initialization of components providing the IDocumentClient implementation. That is, the component is not loaded until it is needed. Such components might be large, and especially if there is more than one, all components might not be needed during an application's lifetime. Creating the components as needed improves the application's performance and resource usage.
For an example of StandardFileCommands's use, see StandardFileCommands.

Topics in this section

Clone this wiki locally