Note

Access to this page requires authorization. You can try signing in or .

Access to this page requires authorization. You can try .

IServiceContainer Interface

Definition

Namespace:
System.ComponentModel.Design
Assemblies:
netstandard.dll, System.ComponentModel.TypeConverter.dll
Assembly:
System.ComponentModel.TypeConverter.dll
Assembly:
System.dll
Assembly:
netstandard.dll
Source:
IServiceObjectContainer.cs
Source:
IServiceObjectContainer.cs

Important

Some information relates to prerelease product that may be substantially modified before it’s released. Microsoft makes no warranties, express or implied, with respect to the information provided here.

Provides a container for services.

public interface class IServiceContainer : IServiceProvider
public interface IServiceContainer : IServiceProvider
[System.Runtime.InteropServices.ComVisible(true)]
public interface IServiceContainer : IServiceProvider
type IServiceContainer = interface
 interface IServiceProvider
[<System.Runtime.InteropServices.ComVisible(true)>]
type IServiceContainer = interface
 interface IServiceProvider
Public Interface IServiceContainer
Implements IServiceProvider
Derived
Attributes
Implements

Examples

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 );
}
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;

namespace ServiceArchitectureExample
{
 // 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. 

 // 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 class ServiceContainerControl : System.Windows.Forms.UserControl, IServiceContainer
 { 
 // List of service instances sorted by key of service type's full name.
 private SortedList localServices; 
 // List that contains the Type for each service sorted by each 
 // service type's full name.
 private SortedList localServiceTypes; 

 // The parent IServiceContainer, or null.
 private IServiceContainer parentServiceContainer; 
 public IServiceContainer serviceParent 
 {
 get
 {
 return parentServiceContainer;
 }
 set
 {
 parentServiceContainer = value;
 // Move any services to parent.
 for( int i=0; i<localServices.Count; i++ )
 parentServiceContainer.AddService(
 (Type)localServiceTypes.GetByIndex(i), 
 localServices.GetByIndex(i));
 localServices.Clear();
 localServiceTypes.Clear();
 }
 }
 
 // The current state of the control reflecting whether it has 
 // obtained or provided a text service.
 private TextServiceState state_;
 public TextServiceState state 
 { 
 get
 {
 return state_;
 }
 set
 {
 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;
 }
 }
 
 // Parent form reference for main program function access.
 private ServiceForm parent; 
 // String for label displayed on the control to indicate 
 // the control's current service-related configuration state.
 public string label; 
 
 public ServiceContainerControl(Size size, Point location, 
 ServiceForm parent) : this(null, size, location, parent){} 
 public ServiceContainerControl(IServiceContainer ParentServiceContainer, 
 Size size, Point location, ServiceForm parent)
 {
 this.state_ = TextServiceState.ServiceNotObtained;
 localServices = new SortedList();
 localServiceTypes = new 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 != null )
 serviceParent = ParentServiceContainer;
 }

 // IServiceProvider.GetService implementation for a linked 
 // service container architecture.
 public new object GetService(System.Type serviceType)
 {
 if( parentServiceContainer != null )
 return parentServiceContainer.GetService(serviceType); 

 object serviceInstance = localServices[serviceType.FullName];
 if( serviceInstance == null )
 {
 return null;
 }
 else if( serviceInstance.GetType() == typeof(ServiceCreatorCallback) )
 {
 // If service instance is a ServiceCreatorCallback, invoke 
 // it to create the service.
 return ((ServiceCreatorCallback)serviceInstance)(this, serviceType); 
 }
 return serviceInstance;
 }
 
 // IServiceContainer.AddService implementation for a linked 
 // service container architecture.
 public void AddService(System.Type serviceType, 
 System.ComponentModel.Design.ServiceCreatorCallback callback, bool promote)
 {
 if( promote && parentServiceContainer != null )
 {
 parentServiceContainer.AddService(serviceType, callback, true);
 }
 else
 {
 localServiceTypes[serviceType.FullName] = serviceType;
 localServices[serviceType.FullName] = callback;
 }
 }
 
 // IServiceContainer.AddService implementation for a linked 
 // service container architecture.
 public void AddService(System.Type serviceType, 
 System.ComponentModel.Design.ServiceCreatorCallback callback)
 {
 AddService(serviceType, callback, true);
 }

 // IServiceContainer.AddService implementation for a linked 
 // service container architecture.
 public void AddService(System.Type serviceType, 
 object serviceInstance, bool promote)
 {
 if( promote && parentServiceContainer != null )
 {
 parentServiceContainer.AddService(serviceType, serviceInstance, true);
 }
 else
 {
 localServiceTypes[serviceType.FullName] = serviceType;
 localServices[serviceType.FullName] = serviceInstance;
 }
 }

 // IServiceContainer.AddService (defaults to promote service addition).
 public void AddService(System.Type serviceType, object serviceInstance)
 {
 AddService(serviceType, serviceInstance, true);
 }

 // IServiceContainer.RemoveService implementation for a linked 
 // service container architecture.
 public void RemoveService(System.Type serviceType, bool promote)
 {
 if( localServices[serviceType.FullName] != null )
 {
 localServices.Remove(serviceType.FullName);
 localServiceTypes.Remove(serviceType.FullName);
 }
 if( promote )
 {
 if( parentServiceContainer != null )
 parentServiceContainer.RemoveService(serviceType);
 }
 }

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

 // Paint method override draws the label string on the control.
 protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
 {
 e.Graphics.DrawString(label, new Font("Arial", 8), 
 new SolidBrush(Color.Black), 5, 5); 
 }

 // Process mouse-down behavior for click.
 protected override void 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 = 
 (TextService)GetService(typeof(TextService));
 if( ts != null )
 {
 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(typeof(TextService)) != null )
 {
 RemoveService(typeof(TextService), true);
 state = TextServiceState.ServiceNotObtained; 
 this.label = "Service Removed"; 
 } 
 }
 else
 {
 // Obtain string and provide text service.
 using (StringInputDialog form =
 new StringInputDialog("Test String"))
 {
 form.StartPosition = FormStartPosition.CenterParent;
 if (form.ShowDialog() == DialogResult.OK)
 {
 if (GetService(typeof(TextService)) != null)
 RemoveService(typeof(TextService), true);
 parent.ResetServiceTree(this, new EventArgs());

 AddService(typeof(TextService),
 new 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 = "Provided Text: " + form.inputTextBox.Text;
 }
 }
 }
 }
 parent.UpdateServiceCoverage();
 }

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

 // Service available. 
 if( state_ == TextServiceState.ServiceNotFound ) 
 this.BackColor = Color.Khaki; 
 else if( state_ == TextServiceState.ServiceNotObtained 
 && label != "Service Removed" )
 this.BackColor = Color.Khaki; 
 }
 }
 
 // ServiceCreatorCallback method creates a text service.
 private object CreateTextService(IServiceContainer container, 
 System.Type serviceType)
 {
 return new TextService("Test Callback");
 }
 }

 // Example form provides UI for demonstrating service sharing behavior 
 // of a network of IServiceContainer/IServiceProvider controls.
 public class ServiceForm : System.Windows.Forms.Form
 {
 // Root service container control for tree.
 private ServiceContainerControl root; 
 // Button for clearing any provided services and resetting tree states.
 private System.Windows.Forms.Button reset_button; 
 // Color list used to color code controls.
 private Color[] colorkeys; 
 // Strings used to reflect text service.
 private string[] keystrings; 

 public ServiceForm()
 {
 InitializeComponent(); 
 colorkeys = new Color[] { Color.Beige, Color.SeaShell, Color.LightGreen, Color.LightBlue, Color.Khaki, Color.CadetBlue };
 keystrings = new string[] { "No service use", "Service not accessible", "Service provided", "Service obtained", "Service accessible", "No further access" };
 CreateServiceControlTree(); 
 }

 private void CreateServiceControlTree()
 {
 // Create root service control
 ServiceContainerControl control1 = new ServiceContainerControl(
 null, new Size(300, 40), new Point(10, 80), this);
 root = control1;
 // Create first tier - pass parent with service object control 1.
 ServiceContainerControl control2 = new ServiceContainerControl(
 control1, new Size(200, 30), new Point(50, 160), this);
 ServiceContainerControl control3 = new ServiceContainerControl(
 control1, new Size(200, 30), new Point(50, 240), this);
 // Create second tier A - pass parent with service object control 2.
 ServiceContainerControl control4 = new ServiceContainerControl(
 control2, new Size(180, 20), new Point(300, 145), this);
 ServiceContainerControl control5 = new ServiceContainerControl(
 control2, new Size(180, 20), new Point(300, 185), this);
 // Create second tier B - pass parent with service object control 3.
 ServiceContainerControl control6 = new ServiceContainerControl(
 control3, new Size(180, 20), new Point(300, 225), this);
 ServiceContainerControl control7 = new ServiceContainerControl(
 control3, new Size(180, 20), new Point(300, 265), this);
 // Add controls
 this.Controls.AddRange( new Control[] { control1, control2, 
 control3, control4, control5, control6, control7 } );
 }

 internal void ResetServiceTree(object sender, EventArgs e)
 {
 // Remove the service from the service tree.
 if( root.GetService(typeof(TextService)) != null ) 
 root.RemoveService(typeof(TextService), 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) ) 
 {
 ((ServiceContainerControl)Controls[i]).state = 
 TextServiceState.ServiceNotObtained;
 ((ServiceContainerControl)Controls[i]).label = string.Empty;
 ((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) ) 
 ((ServiceContainerControl)Controls[i]).ReflectServiceVisibility(); 
 }

 #region Windows Form Designer generated code
 private void InitializeComponent()
 {
 this.reset_button = new System.Windows.Forms.Button();
 this.SuspendLayout();
 // 
 // reset_button
 // 
 this.reset_button.Location = new 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 += new System.EventHandler(this.ResetServiceTree);
 // 
 // ServiceForm
 // 
 this.ClientSize = new System.Drawing.Size(512, 373);
 this.Controls.AddRange(new System.Windows.Forms.Control[] {
 this.reset_button});
 this.MinimumSize = new System.Drawing.Size(520, 400);
 this.Name = "ServiceForm";
 this.Text = "Service Container Architecture Example";
 this.ResumeLayout(false);
 }
 #endregion

 [STAThread]
 static void Main() 
 {
 Application.Run(new ServiceForm());
 }

 protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
 { 
 e.Graphics.DrawString("The following tree diagram represents a "+
 "hierarchy of linked service containers in controls.", 
 new Font("Arial", 9), new SolidBrush(Color.Black), 4, 4);
 e.Graphics.DrawString("This example demonstrates the propagation "+
 "behavior of services through a linked service object tree.", 
 new Font("Arial", 8), new 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.", 
 new Font("Arial", 8), new SolidBrush(Color.Black), 4, 38);
 e.Graphics.DrawString("Left-click a component to update text from "+
 "the text service if available.", new Font("Arial", 8), 
 new SolidBrush(Color.Black), 4, 50);

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

 // Draw color key.
 e.Graphics.DrawRectangle(new Pen(new SolidBrush(Color.Black), 1), 20, 305, 410, 60);
 int y=0;
 for( int i=0; i<3; i++ )
 {
 e.Graphics.FillRectangle(new SolidBrush(colorkeys[y]), 
 25+(i*140), 310, 20, 20); 
 e.Graphics.DrawRectangle(new Pen(new SolidBrush(Color.Black), 1), 
 25+(i*140), 310, 20, 20); 
 e.Graphics.DrawString(keystrings[y], new Font("Arial", 8), 
 new SolidBrush(Color.Black), 50+(i*140), 315);
 y++;
 e.Graphics.FillRectangle(new SolidBrush(colorkeys[y]), 
 25+(i*140), 340, 20, 20); 
 e.Graphics.DrawRectangle(new Pen(new SolidBrush(Color.Black), 1), 
 25+(i*140), 340, 20, 20); 
 e.Graphics.DrawString(keystrings[y], new Font("Arial", 8), 
 new SolidBrush(Color.Black), 50+(i*140), 345);
 y++;
 }
 }
 } 
 
 // Example service type contains a text string, sufficient to 
 // demonstrate service sharing.
 public class TextService
 {
 public string text;

 public TextService() : this(string.Empty)
 {
 }

 public TextService(string text)
 {
 this.text = text;
 }
 }

 public enum TextServiceState
 {
 ServiceNotObtained,
 ServiceObtained,
 ServiceProvided,
 ServiceNotFound
 }

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

 public StringInputDialog(string text)
 {
 InitializeComponent();
 inputTextBox.Text = text;
 }

 private void InitializeComponent()
 {
 this.ok_button = new System.Windows.Forms.Button();
 this.cancel_button = new System.Windows.Forms.Button();
 this.inputTextBox = new System.Windows.Forms.TextBox();
 this.SuspendLayout();
 this.ok_button.Anchor = (System.Windows.Forms.AnchorStyles.Bottom | 
 System.Windows.Forms.AnchorStyles.Right);
 this.ok_button.Location = new 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 = (System.Windows.Forms.AnchorStyles.Bottom | 
 System.Windows.Forms.AnchorStyles.Right);
 this.cancel_button.Location = new 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 = new System.Drawing.Point(6, 9);
 this.inputTextBox.Name = "inputTextBox";
 this.inputTextBox.Size = new System.Drawing.Size(327, 20);
 this.inputTextBox.TabIndex = 0;
 this.inputTextBox.Text = ""; 
 this.inputTextBox.Anchor = ((System.Windows.Forms.AnchorStyles.Top | 
 System.Windows.Forms.AnchorStyles.Left) 
 | System.Windows.Forms.AnchorStyles.Right);
 this.ClientSize = new System.Drawing.Size(342, 73);
 this.Controls.AddRange(new System.Windows.Forms.Control[] {
 this.inputTextBox,
 this.cancel_button,
 this.ok_button});
 this.MinimumSize = new System.Drawing.Size(350, 100);
 this.Name = "StringInputDialog";
 this.Text = "Text Service Provide String Dialog";
 this.ResumeLayout(false);
 }
 }
}
Imports System.Drawing
Imports System.Collections
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Windows.Forms
Imports 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. 

' 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 Class ServiceContainerControl
 Inherits System.Windows.Forms.UserControl
 Implements IServiceContainer

 ' List of service instances sorted by key of service type's full name.
 Private localServices As SortedList
 ' List contains the Type for each service sorted by each service type's full name.
 Private localServiceTypes As SortedList

 ' The parent IServiceContainer, or null.
 Private parentServiceContainer As IServiceContainer

 Public Property serviceParent() As IServiceContainer
 Get
 Return parentServiceContainer
 End Get
 Set(ByVal Value As IServiceContainer)
 parentServiceContainer = Value
 ' Move any services to parent.
 Dim i As Integer
 For i = 0 To localServices.Count - 1
 parentServiceContainer.AddService( _
 CType(localServiceTypes.GetByIndex(i), Type), _
 localServices.GetByIndex(i))
 Next i
 localServices.Clear()
 localServiceTypes.Clear()
 End Set
 End Property

 ' The current state of the control, reflecting whether it has 
 ' obtained or provided a text service.
 Private state_ As TextServiceState

 Public Property state() As TextServiceState
 Get
 Return state_
 End Get
 Set(ByVal Value As TextServiceState)
 If CType(Value, TextServiceState) = _
 TextServiceState.ServiceProvided Then
 Me.BackColor = Color.LightGreen
 ElseIf CType(Value, TextServiceState) = _
 TextServiceState.ServiceNotObtained Then
 Me.BackColor = Color.White
 ElseIf CType(Value, TextServiceState) = _
 TextServiceState.ServiceObtained Then
 Me.BackColor = Color.LightBlue
 ElseIf CType(Value, TextServiceState) = _
 TextServiceState.ServiceNotFound Then
 Me.BackColor = Color.SeaShell
 End If
 state_ = Value
 End Set
 End Property

 ' Parent form reference for main program function access.
 Private Shadows parent As ServiceForm
 ' String for label displayed on the control to indicate 
 ' the control's current service-related configuration state.
 Public label As String

 Public Sub New(ByVal size As Size, ByVal location As Point, _
 ByVal parent As ServiceForm)
 MyClass.New(Nothing, size, location, parent)
 End Sub

 Public Sub New(ByVal ParentServiceContainer As IServiceContainer, _
 ByVal size As Size, ByVal location As Point, ByVal parent As ServiceForm)

 Me.state_ = TextServiceState.ServiceNotObtained
 localServices = New SortedList()
 localServiceTypes = New SortedList()

 Me.BackColor = Color.Beige
 Me.label = String.Empty
 Me.Size = size
 Me.Location = location
 Me.parent = parent
 Me.serviceParent = ParentServiceContainer

 ' If a parent is specified, set the parent property of this 
 ' linkable IServiceContainer implementation.
 If (ParentServiceContainer IsNot Nothing) Then
 serviceParent = ParentServiceContainer
 End If
 End Sub

 ' IServiceProvider.GetService implementation for a linked 
 ' service container architecture.
 Public Shadows Function GetService(ByVal serviceType As System.Type) As Object Implements IServiceProvider.GetService
 If (parentServiceContainer IsNot Nothing) Then
 Return parentServiceContainer.GetService(serviceType)
 End If
 Dim serviceInstance As Object = localServices(serviceType.FullName)
 If serviceInstance Is Nothing Then
 Return Nothing
 ElseIf serviceInstance.GetType() Is GetType(ServiceCreatorCallback) Then
 ' If service instance is a ServiceCreatorCallback, invoke it to create the service
 Return CType(serviceInstance, ServiceCreatorCallback)(Me, serviceType)
 End If
 Return serviceInstance
 End Function

 ' IServiceContainer.AddService implementation for a linked 
 ' service container architecture.
 Public Overloads Sub AddService(ByVal serviceType As System.Type, ByVal callback As System.ComponentModel.Design.ServiceCreatorCallback, ByVal promote As Boolean) Implements IServiceContainer.AddService
 If promote AndAlso (parentServiceContainer IsNot Nothing) Then
 parentServiceContainer.AddService(serviceType, callback, True)
 Else
 localServiceTypes(serviceType.FullName) = serviceType
 localServices(serviceType.FullName) = callback
 End If
 End Sub

 ' IServiceContainer.AddService implementation for a linked 
 ' service container architecture.
 Public Overloads Sub AddService(ByVal serviceType As System.Type, _
 ByVal callback As System.ComponentModel.Design.ServiceCreatorCallback) _
 Implements IServiceContainer.AddService
 AddService(serviceType, callback, True)
 End Sub

 ' IServiceContainer.AddService implementation for a linked 
 ' service container architecture.
 Public Overloads Sub AddService(ByVal serviceType As System.Type, _
 ByVal serviceInstance As Object, ByVal promote As Boolean) _
 Implements IServiceContainer.AddService
 If promote AndAlso (parentServiceContainer IsNot Nothing) Then
 parentServiceContainer.AddService(serviceType, serviceInstance, True)
 Else
 localServiceTypes(serviceType.FullName) = serviceType
 localServices(serviceType.FullName) = serviceInstance
 End If
 End Sub

 ' IServiceContainer.AddService (defaults to promote service addition).
 Public Overloads Sub AddService(ByVal serviceType As System.Type, _
 ByVal serviceInstance As Object) Implements IServiceContainer.AddService
 AddService(serviceType, serviceInstance, True)
 End Sub

 ' IServiceContainer.RemoveService implementation for a linked 
 ' service container architecture.
 Public Overloads Sub RemoveService(ByVal serviceType As System.Type, _
 ByVal promote As Boolean) Implements IServiceContainer.RemoveService
 If (localServices(serviceType.FullName) IsNot Nothing) Then
 localServices.Remove(serviceType.FullName)
 localServiceTypes.Remove(serviceType.FullName)
 End If
 If promote Then
 If (parentServiceContainer IsNot Nothing) Then
 parentServiceContainer.RemoveService(serviceType)
 End If
 End If
 End Sub

 ' IServiceContainer.RemoveService (defaults to promote service removal)
 Public Overloads Sub RemoveService(ByVal serviceType As System.Type) _
 Implements IServiceContainer.RemoveService
 RemoveService(serviceType, True)
 End Sub

 ' Paint method override draws the label string on the control.
 Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
 e.Graphics.DrawString(label, New Font("Arial", 8), New SolidBrush(Color.Black), 5, 5)
 End Sub

 ' Process mouse-down behavior for click.
 Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)

 ' 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 to specify text to provide as a new text 
 ' service, after clearing the tree's services.

 If e.Button = System.Windows.Forms.MouseButtons.Left Then
 If state_ <> TextServiceState.ServiceProvided Then
 ' Attempt to update text from the service, and set 
 ' color state accordingly.
 Dim ts As TextService = CType(GetService(GetType(TextService)), TextService)
 If (ts IsNot Nothing) Then
 Me.label = ts.text
 state = TextServiceState.ServiceObtained
 Else
 Me.label = "Service Not Found"
 state = TextServiceState.ServiceNotFound
 End If
 End If
 End If
 If e.Button = System.Windows.Forms.MouseButtons.Right Then
 If state_ = TextServiceState.ServiceProvided Then
 ' Remove the service the if the container provided it.
 If (GetService(GetType(TextService)) IsNot Nothing) Then
 RemoveService(GetType(TextService), True)
 state = TextServiceState.ServiceNotObtained
 Me.label = "Service Removed"
 End If
 Else
 ' Obtain string and provide text service.
 Using form As New StringInputDialog("Test String")
 form.StartPosition = FormStartPosition.CenterParent
 If form.ShowDialog() = DialogResult.OK Then
 If (GetService(GetType(TextService)) IsNot Nothing) Then
 RemoveService(GetType(TextService), True)
 End If
 parent.ResetServiceTree(Me, New EventArgs())

 AddService(GetType(TextService), _
 New TextService(form.inputTextBox.Text), True)

 ' The following commented method uses a service creator callback.
 ' AddService(typeof(TextService), 
 ' new ServiceCreatorCallback(this.CreateTextService)); 
 state = TextServiceState.ServiceProvided
 Me.label = "Provided Text: " + form.inputTextBox.Text
 End If
 End Using
 End If
 End If
 parent.UpdateServiceCoverage()
 End Sub

 ' Method accesses the TextService to test the visibility of the service 
 ' from the control, and sets the UI state accordingly.
 Public Sub ReflectServiceVisibility()
 If state_ = TextServiceState.ServiceObtained Then
 If GetService(GetType(TextService)) Is Nothing Then
 Me.BackColor = Color.CadetBlue
 End If
 ElseIf state_ <> TextServiceState.ServiceProvided Then
 If GetService(GetType(TextService)) Is Nothing Then
 Me.BackColor = Color.White
 Return
 End If

 ' Service available. 
 If state_ = TextServiceState.ServiceNotFound Then
 Me.BackColor = Color.Khaki
 ElseIf state_ = TextServiceState.ServiceNotObtained _
 AndAlso label <> "Service Removed" Then
 Me.BackColor = Color.Khaki
 End If
 End If
 End Sub

 ' ServiceCreatorCallback method creates a text service.
 Private Function CreateTextService(ByVal container As IServiceContainer, _
 ByVal serviceType As System.Type) As Object
 Return New TextService("Test Callback")
 End Function
End Class

' Example form provides UI for demonstrating service sharing behavior 
' of a network of IServiceContainer/IServiceProvider controls.
Public Class ServiceForm
 Inherits System.Windows.Forms.Form
 
 ' Root service container control for tree.
 Private root As ServiceContainerControl 
 ' Button for clearing any provided services and resetting tree states.
 Private WithEvents reset_button As System.Windows.Forms.Button 
 ' Color list used to color code controls.
 Private colorkeys() As Color
 Private keystrings() As String
 ' Strings used to reflect text service 
 Public Sub New()
 InitializeComponent()
 colorkeys = New Color() {Color.Beige, Color.SeaShell, _
 Color.LightGreen, Color.LightBlue, Color.Khaki, Color.CadetBlue}
 keystrings = New String() {"No service use", "Service not accessible", _
 "Service provided", "Service obtained", "Service accessible", _
 "No further access"}
 CreateServiceControlTree()
 End Sub

 Private Sub CreateServiceControlTree()
 ' Create root service control
 Dim control1 As New ServiceContainerControl(Nothing, New Size(300, 40), New Point(10, 80), Me)
 root = control1
 ' Create first tier - pass parent with service object control 1.
 Dim control2 As New ServiceContainerControl(control1, New Size(200, 30), New Point(50, 160), Me)
 Dim control3 As New ServiceContainerControl(control1, New Size(200, 30), New Point(50, 240), Me)
 ' Create second tier A - pass parent with service object control 2.
 Dim control4 As New ServiceContainerControl(control2, New Size(180, 20), New Point(300, 145), Me)
 Dim control5 As New ServiceContainerControl(control2, New Size(180, 20), New Point(300, 185), Me)
 ' Create second tier B - pass parent with service object control 3.
 Dim control6 As New ServiceContainerControl(control3, New Size(180, 20), New Point(300, 225), Me)
 Dim control7 As New ServiceContainerControl(control3, New Size(180, 20), New Point(300, 265), Me)
 ' Add controls
 Me.Controls.AddRange(New Control() {control1, control2, control3, control4, control5, control6, control7})
 End Sub

 Friend Sub ResetServiceTree(ByVal sender As Object, ByVal e As EventArgs) Handles reset_button.Click
 ' Remove the service from the service tree.
 If (root.GetService(GetType(TextService)) IsNot Nothing) Then
 root.RemoveService(GetType(TextService), True)
 End If
 ' Set all controls to "not obtained" and clear their labels.
 Dim i As Integer
 For i = 0 To Controls.Count - 1
 If Not Controls(i).Equals(reset_button) Then
 CType(Controls(i), ServiceContainerControl).state = TextServiceState.ServiceNotObtained
 CType(Controls(i), ServiceContainerControl).label = String.Empty
 CType(Controls(i), ServiceContainerControl).BackColor = Color.Beige
 End If
 Next i
 End Sub

 Public Sub UpdateServiceCoverage()
 ' Have each control set state to reflect service availability.
 Dim i As Integer
 For i = 0 To Controls.Count - 1
 If Not Controls(i).Equals(reset_button) Then
 CType(Controls(i), ServiceContainerControl).ReflectServiceVisibility()
 End If
 Next i
 End Sub

 Private Sub InitializeComponent()
 Me.reset_button = New System.Windows.Forms.Button()
 Me.SuspendLayout()
 ' 
 ' reset_button
 ' 
 Me.reset_button.Location = New System.Drawing.Point(392, 88)
 Me.reset_button.Name = "reset_button"
 Me.reset_button.TabIndex = 0
 Me.reset_button.TabStop = False
 Me.reset_button.Text = "Reset"
 ' 
 ' ServiceForm
 ' 
 Me.ClientSize = New System.Drawing.Size(512, 373)
 Me.Controls.AddRange(New System.Windows.Forms.Control() {Me.reset_button})
 Me.MinimumSize = New System.Drawing.Size(520, 400)
 Me.Name = "ServiceForm"
 Me.Text = "Service Container Architecture Example"
 Me.ResumeLayout(False)
 End Sub

 <STAThread()> _
 Shared Sub Main()
 Application.Run(New ServiceForm())
 End Sub

 Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
 e.Graphics.DrawString("The following tree diagram represents a hierarchy of linked service containers in controls.", New Font("Arial", 9), New SolidBrush(Color.Black), 4, 4)
 e.Graphics.DrawString("This example demonstrates the propagation behavior of services through a linked service object tree.", New Font("Arial", 8), New 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.", New Font("Arial", 8), New SolidBrush(Color.Black), 4, 38)
 e.Graphics.DrawString("Left-click a component to update text from the text service if available.", New Font("Arial", 8), New SolidBrush(Color.Black), 4, 50)

 ' Draw lines to represent tree branches.
 e.Graphics.DrawLine(New Pen(New SolidBrush(Color.Black), 1), 20, 125, 20, 258)
 e.Graphics.DrawLine(New Pen(New SolidBrush(Color.Black), 1), 21, 175, 45, 175)
 e.Graphics.DrawLine(New Pen(New SolidBrush(Color.Black), 1), 21, 258, 45, 258)
 e.Graphics.DrawLine(New Pen(New SolidBrush(Color.Black), 1), 255, 175, 285, 175)
 e.Graphics.DrawLine(New Pen(New SolidBrush(Color.Black), 1), 255, 258, 285, 258)
 e.Graphics.DrawLine(New Pen(New SolidBrush(Color.Black), 1), 285, 155, 285, 195)
 e.Graphics.DrawLine(New Pen(New SolidBrush(Color.Black), 1), 285, 238, 285, 278)
 e.Graphics.DrawLine(New Pen(New SolidBrush(Color.Black), 1), 285, 155, 290, 155)
 e.Graphics.DrawLine(New Pen(New SolidBrush(Color.Black), 1), 285, 195, 290, 195)
 e.Graphics.DrawLine(New Pen(New SolidBrush(Color.Black), 1), 285, 238, 290, 238)
 e.Graphics.DrawLine(New Pen(New SolidBrush(Color.Black), 1), 285, 278, 290, 278)

 ' Draw color key.
 e.Graphics.DrawRectangle(New Pen(New SolidBrush(Color.Black), 1), 20, 305, 410, 60)
 Dim y As Integer = 0
 Dim i As Integer
 For i = 0 To 2
 e.Graphics.FillRectangle(New SolidBrush(colorkeys(y)), _
 25 + i * 140, 310, 20, 20)
 e.Graphics.DrawRectangle(New Pen(New SolidBrush(Color.Black), 1), _
 25 + i * 140, 310, 20, 20)
 e.Graphics.DrawString(keystrings(y), New Font("Arial", 8), _
 New SolidBrush(Color.Black), 50 + i * 140, 315)
 y += 1
 e.Graphics.FillRectangle(New SolidBrush(colorkeys(y)), _
 25 + i * 140, 340, 20, 20)
 e.Graphics.DrawRectangle(New Pen(New SolidBrush(Color.Black), 1), _
 25 + i * 140, 340, 20, 20)
 e.Graphics.DrawString(keystrings(y), New Font("Arial", 8), _
 New SolidBrush(Color.Black), 50 + i * 140, 345)
 y += 1
 Next i
 End Sub
End Class

' Example service type contains a text string, sufficient to 
' demonstrate service sharing.
Public Class TextService
 Public [text] As String

 Public Sub New()
 MyClass.New(String.Empty)
 End Sub

 Public Sub New(ByVal [text] As String)
 Me.text = [text]
 End Sub
End Class

Public Enum TextServiceState
 ServiceNotObtained
 ServiceObtained
 ServiceProvided
 ServiceNotFound
End Enum

' Example Form for entering a string.
Friend Class StringInputDialog
 Inherits System.Windows.Forms.Form
 Private ok_button As System.Windows.Forms.Button
 Private cancel_button As System.Windows.Forms.Button
 Public inputTextBox As System.Windows.Forms.TextBox

 Public Sub New(ByVal [text] As String)
 InitializeComponent()
 inputTextBox.Text = [text]
 End Sub

 Private Sub InitializeComponent()
 Me.ok_button = New System.Windows.Forms.Button()
 Me.cancel_button = New System.Windows.Forms.Button()
 Me.inputTextBox = New System.Windows.Forms.TextBox()
 Me.SuspendLayout()
 Me.ok_button.Anchor = System.Windows.Forms.AnchorStyles.Bottom _
 Or System.Windows.Forms.AnchorStyles.Right
 Me.ok_button.Location = New System.Drawing.Point(180, 43)
 Me.ok_button.Name = "ok_button"
 Me.ok_button.TabIndex = 1
 Me.ok_button.Text = "OK"
 Me.ok_button.DialogResult = System.Windows.Forms.DialogResult.OK
 Me.cancel_button.Anchor = System.Windows.Forms.AnchorStyles.Bottom _
 Or System.Windows.Forms.AnchorStyles.Right
 Me.cancel_button.Location = New System.Drawing.Point(260, 43)
 Me.cancel_button.Name = "cancel_button"
 Me.cancel_button.TabIndex = 2
 Me.cancel_button.Text = "Cancel"
 Me.cancel_button.DialogResult = System.Windows.Forms.DialogResult.Cancel
 Me.inputTextBox.Location = New System.Drawing.Point(6, 9)
 Me.inputTextBox.Name = "inputTextBox"
 Me.inputTextBox.Size = New System.Drawing.Size(327, 20)
 Me.inputTextBox.TabIndex = 0
 Me.inputTextBox.Text = ""
 Me.inputTextBox.Anchor = System.Windows.Forms.AnchorStyles.Top _
 Or System.Windows.Forms.AnchorStyles.Left Or _
 System.Windows.Forms.AnchorStyles.Right
 Me.ClientSize = New System.Drawing.Size(342, 73)
 Me.Controls.AddRange(New System.Windows.Forms.Control() _
 {Me.inputTextBox, Me.cancel_button, Me.ok_button})
 Me.MinimumSize = New System.Drawing.Size(350, 100)
 Me.Name = "StringInputDialog"
 Me.Text = "Text Service Provide String Dialog"
 Me.ResumeLayout(False)
 End Sub
End Class

Remarks

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.

Methods

Name Description
AddService(Type, Object, Boolean)

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

AddService(Type, Object)

Adds the specified service to the service container.

AddService(Type, ServiceCreatorCallback, Boolean)

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

AddService(Type, ServiceCreatorCallback)

Adds the specified service to the service container.

GetService(Type)

Gets the service object of the specified type.

(Inherited from IServiceProvider)
RemoveService(Type, Boolean)

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

RemoveService(Type)

Removes the specified service type from the service container.

Extension Methods

Name Description
CreateAsyncScope(IServiceProvider)

Creates a new AsyncServiceScope that can be used to resolve scoped services.

CreateScope(IServiceProvider)

Creates a new IServiceScope that can be used to resolve scoped services.

GetKeyedService(IServiceProvider, Type, Object)

Get service of type serviceType from the IServiceProvider.

GetKeyedService<T>(IServiceProvider, Object)

Get service of type T from the IServiceProvider.

GetKeyedServices(IServiceProvider, Type, Object)

Get an enumeration of services of type serviceType from the IServiceProvider.

GetKeyedServices<T>(IServiceProvider, Object)

Get an enumeration of services of type T from the IServiceProvider.

GetRequiredKeyedService(IServiceProvider, Type, Object)

Get service of type serviceType from the IServiceProvider.

GetRequiredKeyedService<T>(IServiceProvider, Object)

Get service of type T from the IServiceProvider.

GetRequiredService(IServiceProvider, Type)

Get service of type serviceType from the IServiceProvider.

GetRequiredService<T>(IServiceProvider)

Get service of type T from the IServiceProvider.

GetService<T>(IServiceProvider)

Get service of type T from the IServiceProvider.

GetServices(IServiceProvider, Type)

Get an enumeration of services of type serviceType from the IServiceProvider.

GetServices<T>(IServiceProvider)

Get an enumeration of services of type T from the IServiceProvider.

Applies to

See also


Feedback

Was this page helpful?