Export (0) Print
Expand All

Walkthrough: Creating Connectable Web Parts in Windows SharePoint Services

Windows SharePoint Services 3

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

This programming task describes how to create two connectable SharePoint Web Parts: a Web Part that can consume a single cell value and another Web Part that can provide a single cell value.

Important noteImportant

Beginning with Windows SharePoint Services 3.0, the SharePoint Web Part infrastructure is built on top of the Microsoft ASP.NET 2.0 Web Part infrastructure and Web Parts that derive from the ASP.NET WebPart class are completely supported in SharePoint, including the ASP.NET connection model. Whenever possible, you should create ASP.NET Web Parts, and use the ASP.NET connection model to connect your Web Parts.

For more information about choosing the best WebPart base class from which to derive, see Developing Web Parts in Windows SharePoint Services. For more information about ASP.NET Web Parts and its connection model, see Web Parts Connections Overview in the ASP.NET documentation.

The SharePoint Web Part infrastructure provides a standardized set of interfaces called connection interfaces that allow Web Parts to exchange information with each other at run time. For example, the List Web Part that is built into Microsoft Windows SharePoint Services can provide (send) a row of data to any other Web Part that can consume (receive) that row, such as a Web Part that implements a form to display the row.

Because the Web Part infrastructure provides a standard set of connection interfaces, connectable Web Parts can be developed by entirely different developers or companies to communicate with one another. A Web Part that supports connection interfaces can be connected by an end user with either Microsoft Office SharePoint Designer 2007 or a Web browser. This allows end users to build sophisticated combinations of Web Parts through a simple menu-driven user interface.

The Windows SharePoint Services connection classes and interfaces are implemented in the Microsoft.SharePoint.WebPartPages.Communication namespace.

Connection Interfaces

Connection interfaces are paired events relevant to a specific item, such as a row in a list. The paired interfaces form a communication bus between Web Parts that implement them. A connectable Web Part raises an interface event to one or more connected parts to make them perform an action. Interfaces are paired as a provider to a consumer. Events from the provider get handled in the consumer and vice versa. The following table briefly describes each pair of connection interfaces.

Connection interface pair

Description

ICellProvider, ICellConsumer

Connection interfaces for providing or consuming a single value item, such as a cell or field.

IRowProvider, IRowConsumer

Connection interfaces for providing or consuming a single row (or multiple rows) of values.

IListProvider, IListConsumer

Connection interfaces for providing or consuming an entire list.

IFilterProvider, IFilterConsumer

Connection interfaces for providing or consuming a filter value. For example, the SharePoint List Web Part supports IListProvider, IRowProvider, and IFilterConsumer. Because IRowProvider can connect to IFilterConsumer, two different SharePoint Lists can be connected to one another. This allows one list to filter the other connected list.

IParametersInProvider, IParametersInConsumer

The IParameterIn interfaces allow passing and receiving of any set of arbitrary parameters between Web Parts. These interfaces cover a situation where the consumer Web Part owns the parameter list and needs to communicate this to other Web Parts.

IParametersOutProvider, IParametersOutConsumer

The IParameterOut interfaces allow passing and receiving of any set of arbitrary parameters between Web Parts. These interfaces cover a situation where the provider Web Part owns the parameter list and needs to communicate this to other Web Parts.

Compatibility Rules

Web Parts can only be connected if they are compatible. Following are several compatibility rules which are assessed by the Web Part infrastructure when determining whether two Web Parts can be connected. If the Web Parts are found to be incompatible, the Connection menu item in the browser is dimmed and a tooltip explains the reason for incompatibility.

Opposite Pairs

A connection interface can only connect with other compatible interfaces. The most basic compatibility rule is that interfaces must be connected as opposite pairs or connected through a transformer. Connecting as opposite pairs means that a Web Part that implements the IRowProvider interface can connect with another part that implements the IRowConsumer interface.

Transformers

In the case where one Web Part needs to connect to another part that doesn’t have the exact same interface, the Web Part infrastructure provides interface transformers, which help users connect two distinct interfaces in a natural and transparent manner.

For example, a user may want to connect a contact list to a picture viewer. However, the contact list only has the IRowProvider interface and the picture viewer only has the ICellConsumer interface. To solve this problem, an interface transformer is provided that allows these two interfaces to connect to each other.

The following table shows the interface pairs that can be connected to one another through a transformer and whether the connections require Microsoft SharePoint Designer 2007.

Transformer

Connect

in browser

Connect in SharePoint Designer

IRowProvider to ICellConsumer

Yes

Yes

IRowProvider to IFilterConsumer

Yes

Yes

IParametersOutProvider to IParametersInConsumer

No

Yes

IRowProvider to IParametersInConsumer

No

Yes

Cross-Page Connections

Some interfaces are allowed to connect to Web Parts on a different page. The behavior is similar to a hyperlink.

You should understand the following about cross-page connections:

  • A Web page editor that is compatible with Microsoft Windows SharePoint Services, such as SharePoint Designer required to author cross-page connections. However, once a cross-page connection has been formed, it can be used by any supported Web browser at run time.

  • Only connectable Web Parts that have implementations designed to run on the server (the CanRunAt method has a ConnectionRunAt value of Server or ServerAndClient) can establish cross-page connections. Connections that are formed on the client side are not allowed to cross Web Pages.

The following table shows the interfaces that can be connected across pages.

When working with cross-page Web Part connections, you must do the following:

Client and Server Connections

At any given time, Web Parts are allowed to run on the client or the server. Some Web Parts, if designed accordingly, can detect the conditions under which they are running and dynamically switch to run on the client or the server. Web Parts can only be connected to other Web Parts running in the same location. For example, server-side parts can only be connected to other server-side parts. Server-side parts cannot be connected to client-side parts. The connection chain must be homogenous. If a part can dynamically switch between client or server connections, the Web Part infrastructure will automatically pin the Web Part to be a client-side or server-side part depending upon the Web Part chain to which it is being connected.

Maximum Number of Connections

When registering an interface, the maximum number of connections to other Web Parts can be specified in the maxConnections parameter of the RegisterInterface method. If the connection limit is exceeded on a Web Part, it cannot be connected to other parts.

The options are 1 or unlimited.

No Circular Connections

A Web Part cannot be connected to itself, either directly or through a chain of connections.

Shared and Private Web Part Connections

A shared Web Part can be connected to a private Web Part, if the private Web Part is a consumer and the shared Web Part supports an unlimited number of connections.

Program Flow

Connected Web Parts pass information to each other by firing specific interface events. When a Web Part implements an interface such as ICellProvider, it must override a number of methods. The firing of the interface events is performed by the Web Part infrastructure calling into the overridden methods at designated times. The following steps for creating connectable Web Parts define which methods need to be overridden and the typical code that a Web Part author should use to do so.

This programming task defines the process of creating a class that implements all of the necessary methods and events for a connection interface using the ICellProvider interface. For a complete code example, refer to the ICellProvider and ICellConsumer source code samples at the end of these steps.

To start this programming task, perform the steps described in Walkthrough: Creating a Basic SharePoint Web Part up to the steps for "Defining the Rendering and Logic of Your Web Part."

Following are 11 high-level steps that you must complete to implement a connection interface for your Web Part:

  1. Create the interface class.

  2. Declare events.

  3. Override the EnsureInterfaces method, and then call the RegisterInterfacemethod.

  4. Override the CanRunAt method.

  5. Override the PartCommunicationConnectmethod.

  6. Override the PartCommunicationInitmethod.

  7. Override the PartCommunicationMainmethod.

  8. Override the GetInitEventArgs method.

  9. Implement the interface event handlers.

  10. Override the RenderWebPartmethod.

  11. Implement supporting methods.

Create a class that implements one of the predefined connection interfaces. In this example, we'll implement the ICellProvider interface. For the remaining steps (2-11), all of the code goes in this class.

Example

public class CellProvider : WebPart, ICellProvider

{
       // Much code goes here. See steps 2 – 11.
}

Declare all of the relevant events for the connection interface. In this location, other variables used by the Web Part are also declared. Because we're working with the ICellProvider interface, the following example declares variables for its CellProviderInit and CellReady events.

Example

// CellProviderInit Event

public event CellProviderInitEventHandler CellProviderInit;

// CellReady Event

public event CellReadyEventHandler CellReady;

Override the EnsureInterfaces method. This method is called by the Web Part infrastructure before the Web Part renders, and is the time when the Web Part should register all of its interfaces by calling one of the two RegisterInterface methods.

Example

public override void EnsureInterfaces()
{
   // Register Interfaces      (See following section) 

}

Within the overridden EnsureInterfaces method, you notify the Web Part infrastructure about the interfaces that will be used by calling the RegisterInterfacemethod. As noted in Step 3, the RegisterInterface method occurs within the EnsureInterfaces method. The RegisterInterface method takes several parameters, which are defined below.

Method Definition

protected InterfaceProperties RegisterInterface(string interfaceName,
                     string interfaceType,
                     int maxConnections,
                     ConnectionRunAt runAtOptions,
                     object interfaceObject,
                     string interfaceClientReference,
                     string menuLabel,
                     string description)
NoteNote

A second RegisterInterface method is available that provides an additional allowCrossPageConnection parameter for specifying explicitly whether an interface supports cross-page connections. The RegisterInterface method that does not include this parameter hard-codes the setting of the allowCrossPageConnection parameter to true for all connection interfaces that are supported by the connection compatibility rules defined by the Web Part infrastructure (see "Cross Page Connections," earlier in this topic). All other connection interfaces are hard coded to false.

Method Parameters

Parameter

Description

interfaceName

A string property that is the friendly name of the interface. The friendly name should be unique within a part. This property cannot contain the following special characters: <, >, &, double quotation mark, single quotation mark, comma, or semicolon.

interfaceType

A property that represents the type of the interface (IRowProvider, ICellConsumer, and so on).

maxConnections

A property that the Web Part infrastructure can query to determine how many connections can be formed on a given interface. maxConnections is an int. It can have a value of WebPart.LimitOneConnection or WebPart.UnlimitedConnections.

runAtOptions

Defines where the interface can run (Client, Server, ClientAndServer, None).

interfaceObject

A reference to the actual object that implements this interface.

interfaceClientReference

For client-side connections, interfaceClientReference is a string that is used as the identifier for the client-side object that implements that interface. This identifier should contain a _WPQ_ to guarantee uniqueness of the name, and it can contain special characters like (). An empty string can be used if the part does not support client-side communication. The Web Part infrastructure encodes double quotation marks as single quotation marks.

NoteNote
WPQ_ is a token that is replaced with a unique identifier by the Web Part infrastructure when a part is rendered.

menuLabel

A general label or explanation of the interface. This will appear in the connection menu user interface. It is recommended that you start your menu label using a verb such as "Provide" or "Consume" so that the user creating a connection understands the direction of the flow of data.

description

An extended description of the interface.

Example

InterfaceProperties myCellProviderInterface = RegisterInterface(
   "MyCellProviderInterface_WPQ_",   //InterfaceName 
   "ICellProvider",         //InterfaceType 
   WebPart.UnlimitedConnections,   //MaxConnections 
   ConnectionRunAt.ServerAndClient,   //RunAtOptions 
   this,               //InterfaceObject 
   "CellProviderInterface_WPQ_",   //InterfaceClientReference 
   "Provide Value From Text Box",         //MenuLabel 
   "Provides the value entered into the text box.");   //Description
NoteNote

To catch code access security permission exceptions, enclose the RegisterInterface call in a try/catch block. For an example of how to do this, see the RegisterInterface method topic.

All connectable Web Parts must override the CanRunAt method. This method is called by the Web Part infrastructure to determine whether a Web Part can be run on the server, the client, or both. The Web Part needs to determine where it can run based on the current configuration of the user's client and the other Web Parts to which it is connected. The values that it can return are the following ConnectionRunAt enumeration values: Client, Server, ClientAndServer, and None. For example, a Web Part may have two different renderings: rich and downlevel. The Web Part may need an ActiveX component installed for its rich rendering. In this case, the CanRunAt method would return Client if the ActiveX component is installed or Server if it isn't installed.

Example

public override ConnectionRunAt CanRunAt()
{
   // This Web Part can run on both the client and the server
   return ConnectionRunAt.ServerAndClient;
}

All connectable Web Parts must override the PartCommunicationConnect method. This method is called by the Web Part infrastructure to notify the Web Part that it has been connected, and to pass along relevant information such as which part it was connected to. This occurs as soon as the Web Part infrastructure links up the appropriate events for the connection. In this method, the Web Part author should keep track of where the interface can be run, create whatever UI controls are needed, and verify that the connection was formed correctly. This method has several parameters which are defined below.

Method Definition

public override void PartCommunicationConnect (string interfaceName, 
                  WebPart connectedPart, 
                  string connectedInterfaceName, 
                  ConnectionRunAt runAt)

Method Parameters

Parameter

Description

interfaceName

Friendly name of the interface that is being connected.

connectedPart

Reference to the other Web Part that is being connected to. Both connectedPart and connectedInterfaceName parameters provide a means for the connecting part to identify the type of part that it is being connected to. This allows the Web Part to establish a more informed interaction with the other part. For example, if the source part has detailed knowledge of the target part, the source part can tap into the target part’s public object model. However, both of these parts need to be designed with this intent for this to work correctly. For example, a chart part and pivot part could be designed to share the same layout of a common data source when they were connected.

connectedInterfaceName

Friendly name of the interface on the other Web Part through which they are connected.

runAt

Where the interface can be executed. This will be either the client or the server and is determined by the Web Part infrastructure based on several factors.

Example

public override void PartCommunicationConnect(string interfaceName,
   WebPart connectedPart,
   string connectedInterfaceName,
   ConnectionRunAt runAt)
{
   // Check to see if this is a client-side part
   if (runAt == ConnectionRunAt.Client)
   {
      // This is a client-side part
      _runAtClient = true;
      return;
   }

   // Must be a server-side part - create the Web Part's controls
   EnsureChildControls(); 

   // Check if this is my particular cell interface
   if (interfaceName == "MyCellProviderInterface_WPQ_")
   {
      // Keep a count of the connections
   _cellConnectedCount++;
   }
}

A connectable Web Part can optionally override the PartCommunicationInit method. This method is called by the Web Part infrastructure to allow the Web Part to fire any initialization events. The Web Part should fire any events that end with "Init" (for example, CellProviderInit).

Init parameters are useful when a Web Part needs to broadcast some information about itself to other parts. For example, when a List part connects to a Form part, the List part could broadcast its field names. The Form part could then render its user interface based on the field names from the List part.

Example

NoteNote

For client-side Web Parts, this event and its event handler must be implemented on the client.

public override void PartCommunicationInit()
{
   //If the connection wasn't formed then don't send Init event
   if(_cellConnectedCount > 0)
   {
      //If there is a listener, send Init event
      if (CellProviderInit != null)
      {
         //Need to create the args for the CellProviderInit event
         CellProviderInitEventArgs cellProviderInitEventArgs = new
         CellProviderInitEventArgs();

         //Set the FieldName
         cellProviderInitEventArgs.FieldName = _cellName;
         cellProviderInitEventArgs.FieldDisplayName = _cellDisplayName;

         //Fire the CellProviderInit event
         CellProviderInit(this, cellProviderInitEventArgs);
      }
   }
}

A connectable Web Part can optionally override the PartCommunicationMain method. This is called by the Web Part infrastructure to allow the Web Part to fire any of the other events from the interface (for example, CellReady). During the execution of the PartCommunicationMain method, the actual communication of data values (as opposed to schema) takes place between Web Parts.

Example

NoteNote

For client-side Web Parts, this event and its event handler must be implemented on the client.

public override void PartCommunicationMain()

{
   // NOTE: THIS CODE IS SPECIFIC TO EACH AND EVERY WEB PART’S IMPLEMENTATION.
   // If the connection wasn't formed then don't send Ready event
   if(_cellConnectedCount > 0)
   {
      // If there is a listener, send CellReady event
      if (CellReady != null)
      {
         // Need to create the args for the CellProviderInit event
         CellReadyEventArgs cellReadyEventArgs = new CellReadyEventArgs();

         // If user clicked button then send the value
         if (_cellClicked)
         {
            // Set the Cell to the value of the TextBox text
            // This is the value that will be sent to the Consumer
            cellReadyEventArgs.Cell = _cellInput.Text;
         }

         else
         {
            // The user didn't actually click the button
            // so just send an empty string to the Consumer
            cellReadyEventArgs.Cell = "";
         }

         // Fire the CellReady event
         // The Consumer will then receive the Cell value
         CellReady(this, cellReadyEventArgs);
      }
   }
}

A connectable Web Part should override the GetInitEventArgs method if needed. The GetInitEventArgs method is only required for the interfaces that use transformers. For example, IRowProvider, ICellConsumer, IFilterConsumer, IParametersOutProvider, and IParametersInConsumer can support transformers. The GetInitEventArgs method is called by the Connection Authoring tools for all the initial data required to create the transformer user interface. The method returns the InitEventArgs object and takes in the interface name.

For example, when connecting two Web Parts that support the IRowProvider and ICellConsumer interfaces, the user needs to specify which field in the IRowProvider Web Part should map to the input value in the ICellConsumer Web Part. This is achieved by the Web Part infrastructure calling the GetInitEventArgs method on each of the interfaces. The connection authoring tools such as Microsoft Office SharePoint Designer 2007 or the browser use the Init parameters passed to build the user interface for the transformer, which allows the user to pick the field mapping.

Method Definition

public override InitEventArgs GetInitEventArgs(string interfaceName)

Method Parameters

Parameter

Description

interfaceName

A string property that is the friendly name of the interface.

Example

NoteNote

This method can be implemented on the server or client.

Important noteImportant

A code example for a Web Part that implements the ICellProvider interface has been used as the example throughout these steps. However, the ICellProvider interface shouldn’t override the GetInitEventArgs method because it can't use a transformer. However, for completeness, following is an example from the CellConsumer.cs code sample at the end of this programming task, which does override the GetInitEventArgs method.

public override InitEventArgs GetInitEventArgs(string interfaceName)
{
   //Check if this is my particular cell interface
   if (interfaceName == "MyCellConsumerInterface_WPQ_")
   {
      EnsureChildControls();

      //Need to create the args for the CellConsumerInit event
      CellConsumerInitEventArgs cellConsumerInitArgs = 
         new CellConsumerInitEventArgs();

      //Set the FieldName and FieldDisplayName
      cellConsumerInitArgs.FieldName = _cellName;
      cellConsumerInitArgs.FieldDisplayName = _cellDisplayName;

      //return the InitArgs
      return(cellConsumerInitArgs);
   }
   else
   {
      return(null);
   }
}

Implement the appropriate event handlers based on the type of interface being used. In this example, the ICellProvider interface must implement the CellConsumerInitEventHandler event handler. This event handler must be implemented whether the data passed by the ICellConsumer interface is used or not. The consumer part will fire this event when its PartCommunicationInitmethod runs.

Method Defintion

public void CellConsumerInit(object sender, CellConsumerInitEventArgs cellConsumerInitEventArgs)

Method Parameters

Parameter

Description

sender

The object calling this method.

cellConsumerInitEventArgs

Parameters passed by the consumer Web Part during the PartCommunicationInit phase.

Example

public void CellConsumerInitEventHandler(object sender, CellConsumerInitEventArgs cellConsumerInitEventArgs)
{
   // This is where the Provider part could see what type of "Cell" 
   //  the Consumer was expecting/requesting.
   // For this simple code example, this information is not used
   // anywhere.

}

All Web Parts must override the RenderWebPart method. The details of this are specific to each and every Web Part. The Web Part infrastructure calls this method to render the Web Part. For a full example, see the CellProvider.cs source code located at end of this programming task topic. For brevity, the following provides a skeleton sample.

Example

protected override void RenderWebPart(HtmlTextWriter output)
{
   // Need to ensure that all of the Web Part's controls are created
   EnsureChildControls();

   // Render client connection code if the connection is client-side
   if (_runAtClient)
   {
      // Script for client-side rendering
   }
   else
   {
      // If connected then display all cell child controls
      if (_cellConnectedCount > 0)
      {
         // Code for server-side rendering
      }

      else
      {
         // There wasn't a cell connection formed,
      }
   }
}

At this location in the ICellProvider source code, all supporting methods should be defined. A skeleton is shown below. For a full example, see the CellProvider.cs source code located at end of this programming task topic.

Example

// Create all controls for this Web Part
protected override void CreateChildControls()
{
   //Code for Child Controls
}

// The Button OnClick event handler
private void CellButtonClicked(object sender, EventArgs e)
{
   _cellClicked = true; //user clicked button, set to true
}

The following two code samples illustrate how to create two connectable Web Parts that implement the ICellProvider and ICellConsumer interfaces.

To complete this programming task, cut and paste the following code samples into two C# files of your Web Part project, and then build your project.

//--------------------------------------------------------------------
// File : CellProvider.cs
//
// Purpose : A sample connectable Web Part that implements the 
//          ICellProvider interface.
//
//---------------------------------------------------------------------

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using Microsoft.SharePoint.WebPartPages;
using Microsoft.SharePoint.WebPartPages.Communication;
using System.Runtime.InteropServices;

namespace ICellDemo
{
   /// <summary>
   /// The CellProvider Web Part class implementes the ICellProvider 
   /// interface. Its UI is very basic - it displays a simple text 
   /// box and button.  The CellConsumer Web Part class implements 
   /// the ICellConsumer interface.  When the CellProvider is
   /// connected to the CellConsumer on a Web Part Page, the CellProvider 
   /// can pass the value in its text box to the CellConsumer which displays 
   /// the value inline.
   /// </summary>
   /// 

   //Step #1: Implement the Connection Interface (ICellProvider)
   public class CellProvider : WebPart, ICellProvider
   {
      //Step #2: Declare Connection Events
      public event CellProviderInitEventHandler CellProviderInit;
      public event CellReadyEventHandler CellReady;

      //Used to keep track of whether or not the connection will be running client-side
      private bool _runAtClient = false;

      //Keep a count of ICell connections
      private int _cellConnectedCount = 0;

      //Web Part UI
      private Button _cellButton;   
      private TextBox _cellInput;
      
      //Cell information
      private string _cellName;
      private string _cellDisplayName;

      //Used to keep track of whether or not the Button in the Web Part was clicked
      private bool _cellClicked = false;


      //Step #3: EnsureInterfaces
      //Notification to the Web Part that is should ensure that all
      //its interfaces are registered using RegisterInterface.
      public override void EnsureInterfaces()
      {
         //Registers an interface for the Web Part
         RegisterInterface("MyCellProviderInterface_WPQ_",  //InterfaceName
            InterfaceTypes.ICellProvider,               //InterfaceType
            WebPart.UnlimitedConnections,               //MaxConnections
            ConnectionRunAt.ServerAndClient,            //RunAtOptions
            this,                                 //InterfaceObject
            "CellProviderInterface_WPQ_",               //InterfaceClientReference
            "Provide String from Textbox",               //MenuLabel
            "Provides a Textbox string");               //Description
      }


      //Step #4: CanRunAt - called by framework to determine where a part can run.
      public override ConnectionRunAt CanRunAt()
      {
         //This Web Part can run on both the client and the server
         return ConnectionRunAt.ServerAndClient;
      }

      //Step #5: PartCommunicationConnect - Notification to the Web Part that it has been connected.
      public override void PartCommunicationConnect(string interfaceName,
         WebPart connectedPart,
         string connectedInterfaceName,
         ConnectionRunAt runAt)
      {
         //Check to see if this is a client-side part
         if (runAt == ConnectionRunAt.Client)
         {
            //This is a client-side part
            _runAtClient = true;
            return;
         }
         
         //Must be a server-side part so need to create the Web Part's controls
         EnsureChildControls(); 

         //Check if this is my particular cell interface
         if (interfaceName == "MyCellProviderInterface_WPQ_")
         {
            //Keep a count of the connections
            _cellConnectedCount++;
         }
      }

      //Step #6: PartCommunicationInit - Notification to the Web Part that it has been connected.
      public override void PartCommunicationInit()
      {
         //If the connection wasn't actually formed then don't want to send Init event
         if(_cellConnectedCount > 0)
         {
            //If there is a listener, send Init event
            if (CellProviderInit != null)
            {
               //Need to create the args for the CellProviderInit event
               CellProviderInitEventArgs cellProviderInitArgs = new CellProviderInitEventArgs();
               
               //Set the FieldName
               cellProviderInitArgs.FieldName = _cellName;
               cellProviderInitArgs.FieldDisplayName = _cellDisplayName;
               
               //Fire the CellProviderInit event.
               CellProviderInit(this, cellProviderInitArgs);
            }
         }
      }

      //Step #7: PartCommunicationMain - Called by the framework to allow part to fire any remaining events
      public override void PartCommunicationMain()
      {
         //If the connection wasn't actually formed then don't want to send Ready event
         if(_cellConnectedCount > 0)
         {
            //If there is a listener, send CellReady event
            if (CellReady != null)
            {
               //Need to create the args for the CellProviderInit event
               CellReadyEventArgs cellReadyArgs = new CellReadyEventArgs();

               //If user clicked button then send the value
               if (_cellClicked)
               {
                  //Set the Cell to the value of the TextBox text
                  //This is the value that will be sent to the Consumer
                  cellReadyArgs.Cell = _cellInput.Text;
               }
               else
               {
                  //The user didn't actually click the button
                  //so just send an empty string to the Consumer
                  cellReadyArgs.Cell = "";
               }

               
               //Fire the CellReady event.
               //The Consumer will then receive the Cell value
               CellReady(this, cellReadyArgs);
            }
         }
      }

      //Step #8: GetInitArgs is not needed in this case. GetInitEventArgs only needs to be
      //implemented for interfaces that can participate in a transformer which are 
      //the following: ICellConsumer, IRowProvider, IFilterConsumer, IParametersOutProvider, 
      //IParametersInConsumer
 
      //Step #9: Implement CellConsumerInit event handler.
      public void CellConsumerInit(object sender, CellConsumerInitEventArgs cellConsumerInitArgs)
      {
         //This is where the Provider part could see what type of "Cell" the Consumer
         //was expecting/requesting.
         //For this simple code example, this information is not used anywhere.
      }

      //Step #10: RenderWebPart - defines Web Part UI and behavior
      protected override void RenderWebPart(HtmlTextWriter output)
      {
         //Need to ensure that all of the Web Part's controls are created
         EnsureChildControls();

         //Render client connection code if the connection is client-side
         if (_runAtClient)
         {
            //Connected client-side
            output.Write(ReplaceTokens("<br><h5>Connected Client-Side</h5><br>\n"
               + "<input type=\"text\" id=\"CellInput_WPQ_\"/>\n"
               + "<button id=\"CellButton_WPQ_\" onclick=\"CellButtonOnClick_WPQ_()\">Fire CellReady</button>\n"
               + "<SCRIPT LANGUAGE=\"JavaScript\">\n"
               + "<!-- \n"
               + "    var CellProviderInterface_WPQ_ = new myCellProviderInterface_WPQ_();\n"

               + "    function myCellProviderInterface_WPQ_()\n"
               + "    {\n"
               + "        this.PartCommunicationInit = myInit;\n"
               + "        this.PartCommunicationMain = myMain;\n"
               + "        this.CellConsumerInit = myCellConsumerInit;\n"

               + "        function myInit()\n"
               + "        {\n"
               + "            var cellProviderInitArgs = new Object();\n"
               + "            cellProviderInitArgs.FieldName = \"CellName\";\n"

               + "            WPSC.RaiseConnectionEvent(\"MyCellProviderInterface_WPQ_\", \"CellProviderInit\", cellProviderInitArgs);\n"
               + "        }\n"

               + "        function myMain()\n"
               + "        {\n"
               + "            var cellReadyArgs = new Object();\n"
                    + "            cellReadyArgs.Cell = \"\";\n"

               + "            WPSC.RaiseConnectionEvent(\"MyCellProviderInterface_WPQ_\", \"CellReady\", cellReadyArgs);\n"
               + "        }\n"

               + "        function myCellConsumerInit(sender, cellConsumerInitArgs)\n"
               + "        {\n"
                + "        }\n"
               + "    }\n"

               + "    function CellButtonOnClick_WPQ_()\n"
               + "    {\n"
               + "        var cellReadyArgs = new Object();\n"
               + "        cellReadyArgs.Cell = document.all(\"CellInput_WPQ_\").value;\n"

               + "        WPSC.RaiseConnectionEvent(\"MyCellProviderInterface_WPQ_\", \"CellReady\", cellReadyArgs);\n"
               + "    }\n"
               + "//-->\n"
               + "</SCRIPT>"));
         }
         else //Connected server-side
         {
            //If connected then display all cell child controls
            if (_cellConnectedCount > 0)
            {
               //Just render some informational text
               output.RenderBeginTag(HtmlTextWriterTag.Br);
               output.RenderEndTag();
               output.RenderBeginTag(HtmlTextWriterTag.H5);
               output.Write("Connected Server-Side");
               output.RenderEndTag();
               output.RenderBeginTag(HtmlTextWriterTag.Br);
               output.RenderEndTag();

               //Render the TextBox control
               _cellInput.RenderControl(output);

               //Render the Button
               _cellButton.RenderControl(output);
            }
            else
            {
               //There wasn't a cell connection formed,
               //so just output a message
               output.Write("NO CELL INTERFACE CONNECTION");
            }
         }
      }

      //Step #11.1 (Supporting Methods): CreateChildControls
      protected override void CreateChildControls()
      {
         //Create the Button
         _cellButton = new Button();
         _cellButton.ID = "CellButton";
         _cellButton.Text = "Fire CellReady";
         Controls.Add(_cellButton);
      
         //Create the TextBox
         _cellInput = new TextBox();
         _cellInput.ID = "CellInput";
         Controls.Add(_cellInput);

         //Set the Cell information.
         //This information will be passed to the Consumer by
         //firing the CellProviderInit event.
         _cellName = "CellInput";
         _cellDisplayName = "CellDisplayInput";
   
         _cellClicked = false; // Initialize to false -- user hasn't clicked yet
         _cellButton.Click += new EventHandler(CellButtonClicked); // listen for Button's click event
      }

      //Step #11.2 (Supporting Methods): CellButtonClicked
      // <param name="sender">The Button object</param>
      // <param name="e">The Event Arguments</param>
      private void CellButtonClicked(object sender, EventArgs e)
      {
         _cellClicked = true; //user clicked button, set to true
      }
   }
}
//--------------------------------------------------------------------
// File : CellConsumer.cs
//
// Purpose : A sample connectable Web Part that implements the 
//          ICellConsumer interface.
//
//---------------------------------------------------------------------
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using Microsoft.SharePoint.WebPartPages;
using Microsoft.SharePoint.WebPartPages.Communication;
using System.Runtime.InteropServices;

namespace ICellDemo
{

   //Step #1: Implement the Connection Interface (ICellConsumer)
   public class CellConsumer : WebPart, ICellConsumer
   {
      
      //Step #2: Declare Connection events
      public event CellConsumerInitEventHandler CellConsumerInit;

      //Used to keep track of whether or not the connection will be running client-side
      private bool _runAtClient = false;

      //Keep a count of ICell connections
      private int _cellConnectedCount = 0;

      //Web Part UI
      private Label _cellLabel;

      //Cell information
      private string _cellName;
      private string _cellDisplayName;

      //Step #3: EnsureInterfaces
      //Notification to the Web Part that is should ensure that all
      //its interfaces are registered using RegisterInterface.
      public override void EnsureInterfaces()
      {
         //Registers an interface for the Web Part.
         RegisterInterface("MyCellConsumerInterface_WPQ_",   //InterfaceName
            InterfaceTypes.ICellConsumer,               //InterfaceType
            WebPart.UnlimitedConnections,               //MaxConnections
            ConnectionRunAt.ServerAndClient,            //RunAtOptions
            this,                                 //InterfaceObject
            "CellConsumerInterface_WPQ_",               //InterfaceClientReference
            "Get String Value",                        //MenuLabel
            "Just a simple ICellConsumer");               //Description
      }

      //Step #4: CanRunAt - called by framework to determine where a part can run.
      public override ConnectionRunAt CanRunAt()
      {
         //This Web Part can run on both the client and the server
         return ConnectionRunAt.ServerAndClient;
      }

      //Step #5: PartCommunicationConnect - Notification to the Web Part that it has been connected.
      public override void PartCommunicationConnect(string interfaceName,
         WebPart connectedPart,
         string connectedInterfaceName,
         ConnectionRunAt runAt)
      {
         //Check to see if this is a client-side part
         if (runAt == ConnectionRunAt.Client)
         {
            //This is a client-side part
            _runAtClient = true;
            return;
         }
         
         //Must be a server-side part so need to create the Web Part's controls
         EnsureChildControls(); 

         //Check if this is my particular cell interface
         if (interfaceName == "MyCellConsumerInterface_WPQ_")
         {
            //Keep a count of the connections
            _cellConnectedCount++;
         }
      }

      //Step #6: PartCommunicationInit - Notification to the Web Part that it has been connected.
      public override void PartCommunicationInit()
      {
         //If the connection wasn't actually formed then don't want to send Init event
         if(_cellConnectedCount > 0)
         {
            //If there is a listener, send init event
            if (CellConsumerInit != null)
            {
               //Need to create the args for the CellConsumerInit event
               CellConsumerInitEventArgs cellConsumerInitArgs = new CellConsumerInitEventArgs();
               
               //Set the FieldNames
               cellConsumerInitArgs.FieldName = _cellName;

               //Fire the CellConsumerInit event.
               //This basically tells the Provider Web Part what type of
               //cell the Consuemr is expecting in the CellReady event.
               CellConsumerInit(this, cellConsumerInitArgs);
            }
         }
      }

      //Step #7: PartCommunicationMain - this method doesn't need to be implemented for the Consumer
      //because the Consumer doesn't have any events that need to be fired during this phase.


      //Step #8: GetInitArgs - called by the connection authoring tool, e.g., browser or SharePoint Designer
      //to get the data required to build the transformer UI.
      public override InitEventArgs GetInitEventArgs(string interfaceName)
      {
         //Check if this is my particular cell interface
         if (interfaceName == "MyCellConsumerInterface_WPQ_")
         {
            EnsureChildControls();

            //Need to create the args for the CellConsumerInit event
            CellConsumerInitEventArgs cellConsumerInitArgs = new CellConsumerInitEventArgs();
               
            //Set the FieldName
            cellConsumerInitArgs.FieldName = _cellName;
            cellConsumerInitArgs.FieldDisplayName = _cellDisplayName;
               
            //return the InitArgs
            return(cellConsumerInitArgs);
         }
         else
         {
            return(null);
         }
      }

      
   
      //Step #9.1: Implement CellProviderInit Event Handler.
      public void CellProviderInit(object sender, CellProviderInitEventArgs cellProviderInitArgs)
      {
         //This is where the Consumer part could see what type of "Cell" the Provider
         //will be sending.
         //For this simple code example, this information is not used anywhere.
      }

      //Step #9.2: Implement CellReady Event Handler. 
      //Set label text based on value from the CellProvider Web Part
      public void CellReady(object sender, CellReadyEventArgs cellReadyArgs)
      {
         //Set the label text to the value of the "Cell" that was passed by the Provider
         if(cellReadyArgs.Cell != null)
         {
            _cellLabel.Text = cellReadyArgs.Cell.ToString();
         }
      }

      //Step #10: RenderWebPart - defines Web Part UI and behavior
      protected override void RenderWebPart(HtmlTextWriter output)
      {
         //Need to ensure that all of the Web Part's controls are created
         EnsureChildControls();

         //Render client connection code if needed
         if (_runAtClient)
         {
            //Connected client-side
            string strClientCode = "<br><h5>Connected Client-Side</h5><br>\n";
            strClientCode += "<div id=\"ConsumerDiv_WPQ_\"/>\n";
            strClientCode += "<SCRIPT LANGUAGE=\"JavaScript\">\n";
            strClientCode += "<!-- \n";
            strClientCode += "    var CellConsumerInterface_WPQ_ = new myCellConsumerInterface_WPQ_();\n";

            strClientCode += "    function myCellConsumerInterface_WPQ_()\n";
            strClientCode += "    {\n";
            strClientCode += "        this.PartCommunicationInit = myInit;\n";
            strClientCode += "        this.CellProviderInit = myCellProviderInit;\n";
            strClientCode += "        this.CellReady = myCellReady;\n";

            strClientCode += "        function myInit()\n";
            strClientCode += "        {\n";
            strClientCode += "            var cellConsumerInitArgs = new Object();\n";
            strClientCode += "            cellConsumerInitArgs.FieldName = \"CellName\";\n";

            strClientCode += "            WPSC.RaiseConnectionEvent(\"MyCellConsumerInterface_WPQ_\", \"CellConsumerInit\", cellConsumerInitArgs);\n";
            strClientCode += "        }\n";

            strClientCode += "        function myCellProviderInit(sender, cellProviderInitArgs)\n";
            strClientCode += "        {\n";
            strClientCode += "        }\n";

            strClientCode += "        function myCellReady(sender, cellReadyArgs)\n";
            strClientCode += "        {\n";
            strClientCode += "            document.all('ConsumerDiv_WPQ_').innerHTML = cellReadyArgs.Cell;\n";
            strClientCode += "        }\n";

            strClientCode += "    }\n";
            strClientCode += "//-->\n";
            strClientCode += "</SCRIPT>";

            output.Write(ReplaceTokens(strClientCode));
         }
         else //Connected server-side
         {
            //If we are connected then display all child controls
            if (_cellConnectedCount > 0)
            {         
               //Just render some informational text
               output.RenderBeginTag(HtmlTextWriterTag.Br);
               output.RenderEndTag();
               output.RenderBeginTag(HtmlTextWriterTag.H5);
               output.Write("Connected Server-Side");
               output.RenderEndTag();
               output.RenderBeginTag(HtmlTextWriterTag.Br);
               output.RenderEndTag();

               //Render the Label control
               _cellLabel.RenderControl(output);
            }
            else
            {
               //else display no connection message
               output.Write("NO CELL INTERFACE CONNECTION");
            }
         }         
      }

      //Step #11.1 (Supporting Methods): CreateChildControls
      protected override void CreateChildControls()
      {
         //Create the Label
         _cellLabel = new Label();
         _cellLabel.ID = "CellLabel";
         Controls.Add(_cellLabel);

         //Set the Cell information.
         //This information will be passed to the Provider by
         //firing the CellConsumerInit event.
         _cellName = "CellInputabc";
         _cellDisplayName = "My CellInput";
      }
   }
}

To deploy and test these sample Web Parts  

  1. Perform the steps described in the "Deploying Your Web" section of the Walkthrough: Creating a Basic SharePoint Web Part programming task, making sure to create a SafeControl block and Web Part Definition file (.dwp) that reflects the appropriate values for your Web Part assembly.

  2. After importing the sample Web Parts into a Web Part Page, connect the Web Parts:

    1. Click Modify Shared Page (or Modify My Page), and then click Design This Page.

    2. Click the Web Part Menu on the Cell Consumer Web Part, point to Connections, point to Consume Cell from, and then click Cell Provider Web Part.

    3. In the Cell Provider Web Part, enter a value into the text box, and then click the Fire CellReady button.

Show:
© 2014 Microsoft