IServiceContainer Interface

 

Provides a container for services.

Namespace:   System.ComponentModel.Design
Assembly:  System (in System.dll)

[ComVisibleAttribute(true)]
public interface class IServiceContainer : IServiceProvider

NameDescription
System_CAPS_pubmethodAddService(Type^, Object^)

Adds the specified service to the service container.

System_CAPS_pubmethodAddService(Type^, Object^, Boolean)

Adds the specified service to the service container, and optionally promotes the service to any parent service containers.

System_CAPS_pubmethodAddService(Type^, ServiceCreatorCallback^)

Adds the specified service to the service container.

System_CAPS_pubmethodAddService(Type^, ServiceCreatorCallback^, Boolean)

Adds the specified service to the service container, and optionally promotes the service to parent service containers.

System_CAPS_pubmethodGetService(Type^)

Gets the service object of the specified type.(Inherited from IServiceProvider.)

System_CAPS_pubmethodRemoveService(Type^)

Removes the specified service type from the service container.

System_CAPS_pubmethodRemoveService(Type^, Boolean)

Removes the specified service type from the service container, and optionally promotes the service to parent service containers.

A service container is, by definition, a service provider. In addition to providing services, it also provides a mechanism for adding and removing services. Services are a foundation of the .NET Framework design-time architecture. Services provide design-time objects access to specific features and methods implemented by a service object that provides a service or services.

To obtain a service at design time, call the GetService method of a component sited in design mode. Designers and other objects can add or remove services at design time through the IDesignerHost interface.

Service containers can be contained by other service containers, forming a tree of service containers. By default, the IServiceContainer interface adds services to the closest service container. When a service is added, it can be added with instructions to promote it. When a service is promoted, it is added to any parent service container, on up until the top of the service container tree is reached. This allows a designer to provide a global service that other objects in the process can use.

The following code example contains the code for a Form that is configured to demonstrate the behavior of a network of linked service containers.

#using <System.Windows.Forms.dll>
#using <System.dll>
#using <System.Drawing.dll>

using namespace System;
using namespace System::Drawing;
using namespace System::Collections;
using namespace System::ComponentModel;
using namespace System::ComponentModel::Design;
using namespace System::Windows::Forms;
using namespace System::Windows::Forms::Design;

// This sample contains a Form class that is configured to demonstrate 
// the behavior of a network of linked service containers.   
// Notes regarding this IServiceContainer and IServiceProvider 
// implementation:
//
// When implementing the IServiceContainer interface, you may want to 
// implement support for a linked service container system
// which enables access to and sharing of services throughout a 
// container tree or network.
//
// To effectively share a service, a GetService, AddService or 
// RemoveService method must be able to locate a service 
// that has been added to a shared service container tree or network.
//        
// One simple approach to sharing services, suitable for container networks 
// where each container has one parent and the tree has
// one parentless container, is to store services only at the top node 
// (the root or grandparent) of a tree.
//
// To store services in the root node of a tree, two types of 
// consistencies must be maintained in the implementation:        
//
//   >   The GetService, AddService and RemoveService implementations 
//       must access the root through some mechanism.
//         The ServiceContainerControl's implementations of these 
//         standard IServiceContainer methods call 
//         the same method of a parent container, if the container 
//         has been parented, to route methods to the root.  
//
//   >   The services must be maintained at the root of the tree; 
//       therefore, any new child's services should be copied to the root.                
ref class ServiceForm;

// forward declaration
public enum class TextServiceState
{
   ServiceNotObtained, ServiceObtained, ServiceProvided, ServiceNotFound
};

// Example service type contains a text string, sufficient to 
// demonstrate service sharing.
public ref class TextService
{
public:
   String^ text;
   TextService()
   {
      this->text = String::Empty;
   }

   TextService( String^ text )
   {
      this->text = text;
   }
};

// ServiceContainerControl provides an example user control implmentation 
// of the IServiceContainer interface. This implementation of 
// IServiceContainer supports a root-node linked service distribution, 
// access. and removal architecture.
public ref class ServiceContainerControl: public System::Windows::Forms::UserControl, public IServiceContainer
{
private:

   // List of service instances sorted by key of service type's full name.
   SortedList^ localServices;

   // List that contains the Type for each service sorted by each 
   // service type's full name.
   SortedList^ localServiceTypes;

   // The parent IServiceContainer, or null.
   IServiceContainer^ parentServiceContainer;

public:

   property IServiceContainer^ serviceParent 
   {
      IServiceContainer^ get()
      {
         return parentServiceContainer;
      }

      void set( IServiceContainer^ value )
      {
         parentServiceContainer = value;

         // Move any services to parent.
         for ( int i = 0; i < localServices->Count; i++ )
            parentServiceContainer->AddService( dynamic_cast<Type^>(localServiceTypes->GetByIndex( i )), localServices->GetByIndex( i ) );
         localServices->Clear();
         localServiceTypes->Clear();
      }
   }

private:

   // The current state of the control reflecting whether it has 
   // obtained or provided a text service.
   TextServiceState state_;

public:

   property TextServiceState state 
   {
      TextServiceState get()
      {
         return state_;
      }

      void set( TextServiceState value )
      {
         if ( (TextServiceState)value == TextServiceState::ServiceProvided )
                  this->BackColor = Color::LightGreen;
         else
         if ( (TextServiceState)value == TextServiceState::ServiceNotObtained )
                  this->BackColor = Color::White;
         else
         if ( (TextServiceState)value == TextServiceState::ServiceObtained )
                  this->BackColor = Color::LightBlue;
         else
         if ( (TextServiceState)value == TextServiceState::ServiceNotFound )
                  this->BackColor = Color::SeaShell;

         state_ = value;
      }
   }

private:

   // Parent form reference for main program function access.
   ServiceForm^ parent;

public:

   // String for label displayed on the control to indicate 
   // the control's current service-related configuration state.
   String^ label;
   ServiceContainerControl( IServiceContainer^ ParentServiceContainer, System::Drawing::Size size, Point location, ServiceForm^ parent )
   {
      this->state_ = TextServiceState::ServiceNotObtained;
      localServices = gcnew SortedList;
      localServiceTypes = gcnew SortedList;
      this->BackColor = Color::Beige;
      this->label = String::Empty;
      this->Size = size;
      this->Location = location;
      this->parent = parent;
      this->serviceParent = ParentServiceContainer;

      // If a parent is specified, set the parent property of this 
      // linkable IServiceContainer implementation.
      if ( ParentServiceContainer != nullptr )
            serviceParent = ParentServiceContainer;
   }

   // IServiceProvider.GetService implementation for a linked 
   // service container architecture.
   virtual Object^ GetService( System::Type^ serviceType ) override
   {
      if ( parentServiceContainer != nullptr )
            return parentServiceContainer->GetService( serviceType );

      Object^ serviceInstance = localServices[ serviceType->FullName ];
      if ( serviceInstance == nullptr )
            return nullptr;
      else
      if ( serviceInstance->GetType() == ServiceCreatorCallback::typeid )
      {
         // If service instance is a ServiceCreatorCallback, invoke 
         // it to create the service.
         return (dynamic_cast<ServiceCreatorCallback^>(serviceInstance));
         (this,serviceType);
      }

      return serviceInstance;
   }

   // IServiceContainer.AddService implementation for a linked 
   // service container architecture.
   virtual void AddService( System::Type^ serviceType, System::ComponentModel::Design::ServiceCreatorCallback^ callback, bool promote )
   {
      if ( promote && parentServiceContainer != nullptr )
            parentServiceContainer->AddService( serviceType, callback, true );
      else
      {
         localServiceTypes[ serviceType->FullName ] = serviceType;
         localServices[ serviceType->FullName ] = callback;
      }
   }

   // IServiceContainer.AddService implementation for a linked 
   // service container architecture.
   virtual void AddService( System::Type^ serviceType, System::ComponentModel::Design::ServiceCreatorCallback^ callback )
   {
      AddService( serviceType, callback, true );
   }

   // IServiceContainer.AddService implementation for a linked 
   // service container architecture.
   virtual void AddService( System::Type^ serviceType, Object^ serviceInstance, bool promote )
   {
      if ( promote && parentServiceContainer != nullptr )
            parentServiceContainer->AddService( serviceType, serviceInstance, true );
      else
      {
         localServiceTypes[ serviceType->FullName ] = serviceType;
         localServices[ serviceType->FullName ] = serviceInstance;
      }
   }

   // IServiceContainer.AddService (defaults to promote service addition).
   virtual void AddService( System::Type^ serviceType, Object^ serviceInstance )
   {
      AddService( serviceType, serviceInstance, true );
   }

   // IServiceContainer.RemoveService implementation for a linked 
   // service container architecture.
   virtual void RemoveService( System::Type^ serviceType, bool promote )
   {
      if ( localServices[ serviceType->FullName ] != nullptr )
      {
         localServices->Remove( serviceType->FullName );
         localServiceTypes->Remove( serviceType->FullName );
      }

      if ( promote )
      {
         if ( parentServiceContainer != nullptr )
                  parentServiceContainer->RemoveService( serviceType );
      }
   }

   // IServiceContainer.RemoveService (defaults to promote 
   // service removal)
   virtual void RemoveService( System::Type^ serviceType )
   {
      RemoveService( serviceType, true );
   }

protected:

   // Paint method override draws the label string on the control.
   virtual void OnPaint( System::Windows::Forms::PaintEventArgs^ e ) override
   {
      e->Graphics->DrawString( label, gcnew System::Drawing::Font( "Arial",8 ), gcnew SolidBrush( Color::Black ), 5, 5 );
   }

   // Process mouse-down behavior for click.
   virtual void OnMouseDown( System::Windows::Forms::MouseEventArgs^ e ) override;

public:

   // Method accesses the TextService to test the visibility of the 
   // service from the control, and sets the UI state accordingly.
   void ReflectServiceVisibility()
   {
      if ( state_ == TextServiceState::ServiceObtained )
      {
         if ( GetService( TextService::typeid ) == nullptr )
                  this->BackColor = Color::CadetBlue;
      }
      else
      if ( state_ != TextServiceState::ServiceProvided )
      {
         if ( GetService( TextService::typeid ) == nullptr )
         {
            this->BackColor = Color::White;
            return;
         }

         // Service available.        
         if ( state_ == TextServiceState::ServiceNotFound )
                  this->BackColor = Color::Khaki;
         else
         if ( state_ == TextServiceState::ServiceNotObtained &&  !label->Equals( "Service Removed" ) )
                  this->BackColor = Color::Khaki;
      }
   }

private:

   // ServiceCreatorCallback method creates a text service.
   Object^ CreateTextService( IServiceContainer^ /*container*/, System::Type^ /*serviceType*/ )
   {
      return gcnew TextService( "Test Callback" );
   }
};

// Example form provides UI for demonstrating service sharing behavior 
// of a network of IServiceContainer/IServiceProvider controls.
public ref class ServiceForm: public System::Windows::Forms::Form
{
private:

   // Root service container control for tree.
   ServiceContainerControl^ root;

   // Button for clearing any provided services and resetting tree states.
   System::Windows::Forms::Button^ reset_button;

   // Color list used to color code controls.
   array<Color>^colorkeys;

   // Strings used to reflect text service.
   array<String^>^keystrings;

public:
   ServiceForm()
   {
      InitializeComponent();
      colorkeys = gcnew array<Color>(6);
      colorkeys[ 0 ] = Color::Beige;
      colorkeys[ 1 ] = Color::SeaShell;
      colorkeys[ 2 ] = Color::LightGreen;
      colorkeys[ 3 ] = Color::LightBlue;
      colorkeys[ 4 ] = Color::Khaki;
      colorkeys[ 5 ] = Color::CadetBlue;
      array<String^>^temp3 = {"No service use","Service not accessible","Service provided","Service obtained","Service accessible","No further access"};
      keystrings = temp3;
      CreateServiceControlTree();
   }

private:
   void CreateServiceControlTree()
   {
      // Create root service control
      ServiceContainerControl^ control1 = gcnew ServiceContainerControl( nullptr,System::Drawing::Size( 300, 40 ),Point(10,80),this );
      root = control1;

      // Create first tier - pass parent with service object control 1.
      ServiceContainerControl^ control2 = gcnew ServiceContainerControl( control1,System::Drawing::Size( 200, 30 ),Point(50,160),this );
      ServiceContainerControl^ control3 = gcnew ServiceContainerControl( control1,System::Drawing::Size( 200, 30 ),Point(50,240),this );

      // Create second tier A - pass parent with service object control 2.
      ServiceContainerControl^ control4 = gcnew ServiceContainerControl( control2,System::Drawing::Size( 180, 20 ),Point(300,145),this );
      ServiceContainerControl^ control5 = gcnew ServiceContainerControl( control2,System::Drawing::Size( 180, 20 ),Point(300,185),this );

      // Create second tier B - pass parent with service object control 3.
      ServiceContainerControl^ control6 = gcnew ServiceContainerControl( control3,System::Drawing::Size( 180, 20 ),Point(300,225),this );
      ServiceContainerControl^ control7 = gcnew ServiceContainerControl( control3,System::Drawing::Size( 180, 20 ),Point(300,265),this );

      // Add controls
      array<Control^>^temp0 = {control1,control2,control3,control4,control5,control6,control7};
      this->Controls->AddRange( temp0 );
   }

internal:
   void ResetServiceTree( Object^ /*sender*/, EventArgs^ /*e*/ )
   {
      // Remove the service from the service tree.
      if ( root->GetService( TextService::typeid ) != nullptr )
            root->RemoveService( TextService::typeid, true );

      // Set all controls to "not obtained" and clear their labels.
      for ( int i = 0; i < Controls->Count; i++ )
         if (  !Controls[ i ]->Equals( reset_button ) )
         {
            (dynamic_cast<ServiceContainerControl^>(Controls[ i ]))->state = TextServiceState::ServiceNotObtained;
            (dynamic_cast<ServiceContainerControl^>(Controls[ i ]))->label = String::Empty;
            (dynamic_cast<ServiceContainerControl^>(Controls[ i ]))->BackColor = Color::Beige;
         }
   }

public:
   void UpdateServiceCoverage()
   {
      // Have each control set state to reflect service availability.
      for ( int i = 0; i < Controls->Count; i++ )
         if (  !Controls[ i ]->Equals( reset_button ) )
                  (dynamic_cast<ServiceContainerControl^>(Controls[ i ]))->ReflectServiceVisibility();
   }

private:
   void InitializeComponent()
   {
      this->reset_button = gcnew System::Windows::Forms::Button;
      this->SuspendLayout();

      // 
      // reset_button
      // 
      this->reset_button->Location = System::Drawing::Point( 392, 88 );
      this->reset_button->Name = "reset_button";
      this->reset_button->TabIndex = 0;
      this->reset_button->TabStop = false;
      this->reset_button->Text = "Reset";
      this->reset_button->Click += gcnew System::EventHandler( this, &ServiceForm::ResetServiceTree );

      // 
      // ServiceForm
      // 
      this->ClientSize = System::Drawing::Size( 512, 373 );
      array<System::Windows::Forms::Control^>^temp1 = {this->reset_button};
      this->Controls->AddRange( temp1 );
      this->MinimumSize = System::Drawing::Size( 520, 400 );
      this->Name = "ServiceForm";
      this->Text = "Service Container Architecture Example";
      this->ResumeLayout( false );
   }

protected:
   virtual void OnPaint( System::Windows::Forms::PaintEventArgs^ e ) override
   {
      e->Graphics->DrawString( "The following tree diagram represents a "
      "hierarchy of linked service containers in controls.", gcnew System::Drawing::Font( "Arial",9 ), gcnew SolidBrush( Color::Black ), 4, 4 );
      e->Graphics->DrawString( "This example demonstrates the propagation "
      "behavior of services through a linked service object tree.", gcnew System::Drawing::Font( "Arial",8 ), gcnew SolidBrush( Color::Black ), 4, 26 );
      e->Graphics->DrawString( "Right-click a component to add or replace a "
      "text service, or to remove it if the component provided it.", gcnew System::Drawing::Font( "Arial",8 ), gcnew SolidBrush( Color::Black ), 4, 38 );
      e->Graphics->DrawString( "Left-click a component to update text from "
      "the text service if available.", gcnew System::Drawing::Font( "Arial",8 ), gcnew SolidBrush( Color::Black ), 4, 50 );

      // Draw lines to represent tree branches.
      e->Graphics->DrawLine( gcnew Pen( gcnew SolidBrush( Color::Black ),1 ), 20, 125, 20, 258 );
      e->Graphics->DrawLine( gcnew Pen( gcnew SolidBrush( Color::Black ),1 ), 21, 175, 45, 175 );
      e->Graphics->DrawLine( gcnew Pen( gcnew SolidBrush( Color::Black ),1 ), 21, 258, 45, 258 );
      e->Graphics->DrawLine( gcnew Pen( gcnew SolidBrush( Color::Black ),1 ), 255, 175, 285, 175 );
      e->Graphics->DrawLine( gcnew Pen( gcnew SolidBrush( Color::Black ),1 ), 255, 258, 285, 258 );
      e->Graphics->DrawLine( gcnew Pen( gcnew SolidBrush( Color::Black ),1 ), 285, 155, 285, 195 );
      e->Graphics->DrawLine( gcnew Pen( gcnew SolidBrush( Color::Black ),1 ), 285, 238, 285, 278 );
      e->Graphics->DrawLine( gcnew Pen( gcnew SolidBrush( Color::Black ),1 ), 285, 155, 290, 155 );
      e->Graphics->DrawLine( gcnew Pen( gcnew SolidBrush( Color::Black ),1 ), 285, 195, 290, 195 );
      e->Graphics->DrawLine( gcnew Pen( gcnew SolidBrush( Color::Black ),1 ), 285, 238, 290, 238 );
      e->Graphics->DrawLine( gcnew Pen( gcnew SolidBrush( Color::Black ),1 ), 285, 278, 290, 278 );

      // Draw color key.
      e->Graphics->DrawRectangle( gcnew Pen( gcnew SolidBrush( Color::Black ),1 ), 20, 305, 410, 60 );
      int y = 0;
      for ( int i = 0; i < 3; i++ )
      {
         e->Graphics->FillRectangle( gcnew SolidBrush( colorkeys[ y ] ), 25 + (i * 140), 310, 20, 20 );
         e->Graphics->DrawRectangle( gcnew Pen( gcnew SolidBrush( Color::Black ),1 ), 25 + (i * 140), 310, 20, 20 );
         e->Graphics->DrawString( keystrings[ y ], gcnew System::Drawing::Font( "Arial",8 ), gcnew SolidBrush( Color::Black ), 50.0f + (i * 140), 315.0f );
         y++;
         e->Graphics->FillRectangle( gcnew SolidBrush( colorkeys[ y ] ), 25 + (i * 140), 340, 20, 20 );
         e->Graphics->DrawRectangle( gcnew Pen( gcnew SolidBrush( Color::Black ),1 ), 25 + (i * 140), 340, 20, 20 );
         e->Graphics->DrawString( keystrings[ y ], gcnew System::Drawing::Font( "Arial",8 ), gcnew SolidBrush( Color::Black ), 50.0f + (i * 140), 345.0f );
         y++;

      }
   }
};

// Example Form for entering a string.
private ref class StringInputDialog: public System::Windows::Forms::Form
{
private:
   System::Windows::Forms::Button^ ok_button;
   System::Windows::Forms::Button^ cancel_button;

public:
   System::Windows::Forms::TextBox^ inputTextBox;
   StringInputDialog( String^ text )
   {
      InitializeComponent();
      inputTextBox->Text = text;
   }

private:
   void InitializeComponent()
   {
      this->ok_button = gcnew System::Windows::Forms::Button;
      this->cancel_button = gcnew System::Windows::Forms::Button;
      this->inputTextBox = gcnew System::Windows::Forms::TextBox;
      this->SuspendLayout();
      this->ok_button->Anchor = static_cast<System::Windows::Forms::AnchorStyles>(System::Windows::Forms::AnchorStyles::Bottom | System::Windows::Forms::AnchorStyles::Right);
      this->ok_button->Location = System::Drawing::Point( 180, 43 );
      this->ok_button->Name = "ok_button";
      this->ok_button->TabIndex = 1;
      this->ok_button->Text = "OK";
      this->ok_button->DialogResult = System::Windows::Forms::DialogResult::OK;
      this->cancel_button->Anchor = static_cast<System::Windows::Forms::AnchorStyles>(System::Windows::Forms::AnchorStyles::Bottom | System::Windows::Forms::AnchorStyles::Right);
      this->cancel_button->Location = System::Drawing::Point( 260, 43 );
      this->cancel_button->Name = "cancel_button";
      this->cancel_button->TabIndex = 2;
      this->cancel_button->Text = "Cancel";
      this->cancel_button->DialogResult = System::Windows::Forms::DialogResult::Cancel;
      this->inputTextBox->Location = System::Drawing::Point( 6, 9 );
      this->inputTextBox->Name = "inputTextBox";
      this->inputTextBox->Size = System::Drawing::Size( 327, 20 );
      this->inputTextBox->TabIndex = 0;
      this->inputTextBox->Text = "";
      this->inputTextBox->Anchor = static_cast<System::Windows::Forms::AnchorStyles>(System::Windows::Forms::AnchorStyles::Top | System::Windows::Forms::AnchorStyles::Left | System::Windows::Forms::AnchorStyles::Right);
      this->ClientSize = System::Drawing::Size( 342, 73 );
      array<System::Windows::Forms::Control^>^temp4 = {this->inputTextBox,this->cancel_button,this->ok_button};
      this->Controls->AddRange( temp4 );
      this->MinimumSize = System::Drawing::Size( 350, 100 );
      this->Name = "StringInputDialog";
      this->Text = "Text Service Provide String Dialog";
      this->ResumeLayout( false );
   }
};

void ServiceContainerControl::OnMouseDown( System::Windows::Forms::MouseEventArgs^ e )
{
   //  This example control responds to mouse clicks as follows:
   //
   //      Left click - control attempts to obtain a text service 
   //      and sets its label text to the text provided by the service
   //      Right click - if the control has already provided a text 
   //      service, this control does nothing. Otherwise, the control 
   //      shows a dialog box to specify text to provide as a new text 
   //      service, after clearing the tree's services.
   if ( e->Button == ::MouseButtons::Left )
   {
      if ( state_ != TextServiceState::ServiceProvided )
      {
         // Attempt to update text from service, and set 
         // color state accordingly.
         TextService^ ts = dynamic_cast<TextService^>(GetService( TextService::typeid ));
         if ( ts != nullptr )
         {
            this->label = ts->text;
            state = TextServiceState::ServiceObtained;
         }
         else
         {
            this->label = "Service Not Found";
            state = TextServiceState::ServiceNotFound;
         }
      }
   }

   if ( e->Button == ::MouseButtons::Right )
   {
      if ( state_ == TextServiceState::ServiceProvided )
      {
         // Remove the service if the container provided it.
         if ( GetService( TextService::typeid ) != nullptr )
         {
            RemoveService( TextService::typeid, true );
            state = TextServiceState::ServiceNotObtained;
            this->label = "Service Removed";
         }
      }
      else
      {
         // Obtain string and provide text service.
         StringInputDialog^ form = gcnew StringInputDialog( "Test String" );
         form->StartPosition = FormStartPosition::CenterParent;
         if ( form->ShowDialog() == DialogResult::OK )
         {
            if ( GetService( TextService::typeid ) != nullptr )
                        RemoveService( TextService::typeid, true );
            parent->ResetServiceTree( this, gcnew EventArgs );
            AddService( TextService::typeid, gcnew TextService( form->inputTextBox->Text ), true );

            // The following commented method uses a service creator callback.
            // AddService(typeof(TextService), 
            //  new ServiceCreatorCallback(this.CreateTextService));                                                
            state = TextServiceState::ServiceProvided;
            this->label = String::Format( "Provided Text: {0}", form->inputTextBox->Text );
         }
      }
   }

   parent->UpdateServiceCoverage();
}

[STAThread]
int main()
{
   Application::Run( gcnew ServiceForm );
}

.NET Framework
Available since 1.1
Return to top
Show: