-
Notifications
You must be signed in to change notification settings - Fork 263
How MEF is Used in ATF
The best way to see how ATF uses MEF is to look at the ATF samples and ATF components. This section examines code in detail to show what's required to use MEF.
In MEF, you need to add components (parts) to a MEF catalog. There are several kinds of MEF catalogs, deriving from the base class ComposablePartCatalog
.
Components are what MEF refers to as composable parts. These parts can be put together — composed — into a cohesive whole in the application, where the parts are instantiated and meet each others' import and export contracts, specified by their attributes. This process of putting parts together is called composition.
ATF mainly uses TypeCatalog
, which creates a catalog from a collection of types. In ATF, you don't need to instantiate or directly access components to use them in your application. Instead, you simply list them in the TypeCatalog
in the application's Main()
function, followed by some standard initialization. Each of the parts listed in the catalog is instantiated by MEF, that is, an instance of each class is created during composition. In some cases, more than one instance may be created, depending on the Part Creation Policy.
Here is a typical block of sample code setting up a MEF catalog from the Main()
function in Program.cs
for the ATF Simple DOM Editor Sample (link to source):
var catalog = new TypeCatalog(
typeof(SettingsService), // persistent settings and user preferences dialog
typeof(StatusService), // status bar at bottom of main Form
typeof(CommandService), // handles commands in menus and toolbars
typeof(ControlHostService), // docking control host
...
typeof(AtfScriptVariables), // exposes common ATF services as script variables
typeof(AutomationService) // provides facilities to run an automated script using the .NET remoting service
);
TypeCatalog
's constructor lists all the types of the components the application uses, one parameter for each type.
Occasionally ATF uses other catalogs besides TypeCatalog
. This code, from the StandardInteropParts
class, creates a TypeCatalog
and returns it as a ComposablePartCatalog
type property (link to source):
/// Gets type catalog for all components</summary>
public static ComposablePartCatalog Catalog
{
get
{
return new TypeCatalog(
typeof(MainWindowAdapter),
typeof(ContextMenuService),
typeof(DialogService),
typeof(ControlHostServiceAdapter)
);
}
}
The ATF Simple DOM Editor WPF Sample creates its own TypeCatalog
and then uses it and the preceding ComposablePartCatalog
from StandardInteropParts
(plus a similar catalog from StandardViewModels
) to create an AggregateCatalog
(link to source):
protected override AggregateCatalog GetCatalog()
{
var typeCatalog = new TypeCatalog(
typeof(ControlHostService), // Docking framework
typeof(MainWindow), // Application's main window
... //omitted types
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);
}
An AggregateCatalog
is a catalog that combines elements of ComposablePartCatalog
objects and also derives from ComposablePartCatalog
.
The ATF Simple DOM Editor WPF Sample uses the AggregateCatalog
as a convenience to combine several catalogs. Later on, it uses this catalog similarly to the way other samples use TypeCatalog
.
After creating a catalog of components, samples use the catalog to initiate MEF's composition process.
Here's how ATF Simple DOM Editor Sample does it (link to source):
// Set up the MEF container with these components
var container = new CompositionContainer(catalog);
...
// Give components a chance to clean up.
container.Dispose();
This shows a fairly typical code sequence of how samples use the catalog and kick off the process of components discovering each other.
The following sections describe these MEF operations in detail. Some of the code here, such as creating the main form and toolstrip, is not MEF-related.
A CompositionContainer
is a container of components that manages composing the components (parts).
This line creates a CompositionContainer
object for the catalog:
// Create the MEF container for the composable parts
CompositionContainer container = new CompositionContainer(catalog);
A CompositionBatch
is a set of parts (components) that can be added to a CompositionContainer
. MainForm
is also a component class. This next section of code from ATF Simple DOM Editor Sample adds the main form to the CompositionBatch
(link to source):
var batch = new CompositionBatch();
...
batch.AddPart(mainForm);
AddPart()
creates a composable part from mainForm
and adds it to batch
.
Here is the main line of this whole sequence:
container.Compose(batch);
Compose()
adds the parts in batch
to the parts in the container and composes these parts, creating an object for each part and making sure they meet each other's import and export contracts.
The comment here from ATF Simple DOM Editor Sample pretty well explains what's going on (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();
Invoking InitializeAll() on the container causes the IInitializable.Initialize()
method to be executed in every component. InitializeAll() is actually an extension method on CompositionContainer
provided by ATF's MefUtil
class. Every ATF component should implement IInitializable
, that is, implement the IInitializable.Initialize()
method. InitializeAll()
performs other functions as well, described in IInitializable.
When the application terminates, this final statement in Program.cs
of ATF Simple DOM Editor Sample releases all resources used by the CompositionContainer
(link to source):
// Give components a chance to clean up.
container.Dispose();
ATF uses a limited set of MEF attributes in its components. These are mainly used to specify exported and imported items. However, the Export attributes decorating ATF source are not just about exports and imports. For more information, see Initializing Components.
Export
attributes nearly always apply to classes. That is, ATF mainly exports its component classes. Some samples export fields.
The Export
attribute is used in the component to announce its presence to the world: its contract, which is essentially a string that importers use to find this component. It is nearly always of this form:
[Export(typeof(type)]
where type is the type of the component, usually its class name.
Multiple Export attributes are sometime used, as in this example from StandardFileExitCommand
(link to source):
[Export(typeof(StandardFileExitCommand))]
[Export(typeof(IInitializable))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class StandardFileExitCommand : ICommandClient, IInitializable, IPartImportsSatisfiedNotification
ATF often provides a variety of Export attributes on a class, one for each important interface that the class implements, and sometimes for whatever base classes there might be, too. The ATF designers try to anticipate how client code might use ATF components, so ATF provides more Exports than ATF's own code Imports. The attribute [Export(typeof(IInitializable))]
has an additional purpose, described in Initializing Components.
[ExportMetadata()]
is little used.
[Import]
is often used, and it only rarely specifies a type, as in the EditLabelCommand
component (link to source):
[Import(typeof(ICommandService))]
private Sce.Atf.Applications.ICommandService m_commandService = null;
Nearly all imports apply to fields and constructors, and to a few properties. Imports are mainly used to connect components to each other. For more information, see Using ATF Components.
Defaults are frequently allowed:
[Import(AllowDefault = true)]
This allows the importer to be set to its type's default value when a matching export could not be found. Defaults are only occasionally not permitted.
For an example of getting a component from an import, see Getting a SettingsService Object.
Note that during composition, the parameter-less constructor is used by default to instantiate the component. To make the composition engine use a different constructor, mark it with the [ImportingConstructor]
attribute. ATF often uses this attribute, as in this sample component from the ATF DOM Property Editor Sample (link to source):
[ImportingConstructor]
public Editor(
IContextRegistry contextRegistry,
IDocumentRegistry documentRegistry,
TreeLister treeLister,
SchemaLoader schemaLoader)
Note also that all the constructor parameters for the constructor decorated with [ImportingConstructor]
are in effect decorated as [Import]
.
This attribute is nearly always Shared
:
[PartCreationPolicy(CreationPolicy.Shared)]
Shared
means a single instance of the associated component is created by the CompositionContainer
during composition and shared by all importers.
A few of these are used:
[PartCreationPolicy(CreationPolicy.Any)]
This means the most appropriate creation policy is used, and defaults to Shared
.
A few times AllowRecomposition = true
is used, but never AllowRecomposition = false
.
ComponentModel provides some other classes that ATF occasionally uses.
The System.ComponentModel.Composition.Hosting.ExportProvider
class has methods to get exported components, when it is not convenient to use an [Import]
attribute for some reason.
For example, the ATF DOM Property Editor Sample uses one of these methods to get references to a component in its Program.cs
Main()
function. Such components are often used as parameters in an importing constructor.
The ExportProvider.GetExportedValue<T>()
method gets the exported object with the contract name derived from the specified type parameter. In this example from ATF DOM Property Editor Sample, container
is an object in the CompositionContainer
class, which derives from ExportProvider
(link to source):
container.InitializeAll();
var propEditor = container.GetExportedValue<PropertyEditor>();
propEditor.PropertyGrid.PropertySorting = Sce.Atf.Controls.PropertyEditing.PropertySorting.Categorized;
After the imported PropertyEditor
component is obtained, its PropertyGrid
property is used to set a default for property sorting.
Note that GetExportedValue()
is called after all components are initialized.
ATF implements this interface mainly in its classes that directly support WinForms and WPF, such as classes in the Application Shell Framework, as described in ATF Frameworks.
- What is MEF: Brief description of MEF with links to more detailed information.
- How MEF is Used in ATF: Examine how ATF is used in sample applications to compose components and how components are decorated.
- Initializing Components: How component initialization is implemented in ATF.
- Using ATF Components: How to use ATF components, discovering what you need to provide in your application.
- Creating MEF Components: How to create components of your own, using the attributes you need.
- Important ATF Components: Description of some key ATF components in functional areas as well as some components in sample applications.
- Finding ATF Components: How to find components you need for your application.
- Details on Selected ATF Components: Provides more details on some ATF components you might want to use in your applications.
- Details on Using Selected ATF Components: Shows exactly how to use certain components.
- Home
- Getting Started
- Features & Benefits
- Requirements & Dependencies
- Gallery
- Technology & Samples
- Adoption
- News
- Release Notes
- ATF Community
- Searching Documentation
- Using Documentation
- Videos
- Tutorials
- How To
- Programmer's Guide
- Reference
- Code Samples
- Documentation Files
© 2014-2015, Sony Computer Entertainment America LLC