Containers, Sites, and Components

A container is a specialized collection object that provides logical containment for one or more components. Containers manage the interaction of the components with each other, as well as with the external application environment, by providing an implementation of the ISite interface through which interactions can take place. The container allows tracking of your components on a first-in, first-out basis, and allows you to refer to your components by an index. The container also provides for a means of common disposal of your components when you no longer have need for them.

Containment refers to logical containment, not visual or physical containment. The container encapsulates one or more components and provides a wrapper through which clients may interact. The container allows you to add and remove components via the following syntax:

Imports System.ComponentModel
Dim myComponent As New Component()
Dim myContainer As New Container()
myContainer.Add(myComponent)
myContainer.Remove(myComponent)
using System.ComponentModel;
Component myComponent = new Component();
Container myContainer = new Container();
myContainer.Add(myComponent);
myContainer.Remove(myComponent);

A component container will either be an instance of the Container class, or an implementation of the IContainer interface. Container is the reference implementation of this interface.

Specifying a Component Name

You can also specify a name for your component within the container. This name must be unique within the container, and is specified using the Add method.

Dim myComponent As New Component()
Dim myContainer As New Container()
MyContainer.Add(myComponent, "ThisComponent")
Component myComponent = new Component();
Container myContainer = new Container();
myContainer.Add(myComponent, "ThisComponent");

Managing Resources and Extending Containers

Containers provide a central means of managing the resources associated with your components. When the Dispose method is called, the container automatically calls the Dispose method of all the contained components, thereby ensuring that resources are released promptly.

Containers are extensible. You can create your own class that inherits from Container that incorporates custom functionality. For example, you might create a container that enforced rules that govern which components may be added to the container, as is shown in the following example:

Public Class MyContainer
   Inherits Container
   Public Overloads Overrides Sub Add(ByVal component As IComponent)
      ' Checks to see if the component is allowed to join this container.
      If TypeOf component Is Widget Then
         ' Calls the Add method of the base class, and adds the component.
         MyBase.Add(component)
      Else
         ' If the component is not allowed, an exception is thrown.
         Throw New NonWidgetException()
      End If
   End Sub
End Class
class MyContainer : Container
{
   public override void Add(IComponent component)
   {
      // Checks to see if the component is allowed to join this container.
      if (component is Widget)
      {
         base.Add(component);
      }
      else
      {
         throw new NonWidgetException();
      }
   }
}

The previous example creates a new container class that is able to enforce a rule about which components are able to join the container. If a component is not of the specified class (in this case, Widget), then an exception is thrown.

When a component is added to a container, the container creates a site for it. This is an implementation of the ISite interface that is exposed through the component's Site property. Communication by a component with its host container is accomplished via the component's Site property. This property represents the logical site of the component, and is hosted by the container. A component that is not contained in a container returns a null reference for its Site property. The Site property allows you to obtain a reference to the container interface through the ISite.Container property, or a reference to the component interface being hosted through the Component property.

Dim myComponent As New Component
Dim myContainer As New Container
myContainer.Add(myComponent)
Dim myIComponent as IComponent
Dim myIContainer as IContainer
myIComponent = myComponent.Site.Component
myIContainer = myComponent.Site.Container
' These two messages display True.
MessageBox.Show("Are the components equal? " & _
   myComponent.Equals(myIComponent).ToString)
MessageBox.Show("Are the containers equal? " & _
   myContainer.Equals(myIContainer).ToString)
Component myComponent = new Component();
Container myContainer = new Container();
myContainer.Add(myComponent);
IComponent myIComponent;
IContainer myIContainer;
myIComponent = myComponent.Site.Component;
myIContainer = myComponent.Site.Container;
MessageBox.Show("Are the components equal? " + 
   myComponent.Equals(myIComponent).ToString());
MessageBox.Show("Are the containers equal? " + 
   myContainer.Equals(myIContainer).ToString());

Both of these properties return only the interface associated with these objects, not a reference to the objects themselves. Note that the component also has a Container property that returns the same interface as Container. This property is provided by through the site and can be thought of as a shortcut.

If you assign a name to your component using the Add method, the name can be retrieved via the Name property. If the container has a service object associated with it, a reference to that object can be obtained by the component via the GetService method.

Accessing Services

You can access a variety of services through the GetService method. These services provide extensive support for integrating your components into the design environment. For more information, see How to: Access Design-Time Services and Design-Time Architecture.

See Also

Tasks

How to: Create Component Containers

How to: Extend Component Containers

How to: Access Design-Time Services

Concepts

Communication Between Containers and Components

Design-Time Architecture