Walkthrough: Creating Connectable Web Parts in Windows SharePoint Services
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
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.
About Connectable Web Parts
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 |
---|---|
Connection interfaces for providing or consuming a single value item, such as a cell or field. |
|
Connection interfaces for providing or consuming a single row (or multiple rows) of values. |
|
Connection interfaces for providing or consuming an entire list. |
|
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. |
|
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. |
|
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 |
---|---|---|
Yes |
Yes |
|
Yes |
Yes |
|
No |
Yes |
|
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.
Source page interface |
Target page interface |
---|---|
When working with cross-page Web Part connections, you must do the following:
Pass ConnectionRunAt.Server or ConnectionRunAt.ServerAndClient to the runAtOptions parameter of the RegisterInterface method.
Pass true to the allowCrossPageConnection parameter of the RegisterInterface method.
Implement the GetInitEventArgs method to provide specific information about data that is passed through the connection interface.
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.
WebPart.UnlimitedConnections specifies that a connectable Web Part can accept an unlimited number of connections to another Web Part.
WebPart.LimitOneConnection specifies that a connectable Web Part can accept only one connection.
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.
Creating a Web Part that Implements the ICellProvider Interface
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:
Create the interface class.
Declare events.
Override the EnsureInterfaces method, and then call the RegisterInterfacemethod.
Override the CanRunAt method.
Override the PartCommunicationConnectmethod.
Override the PartCommunicationInitmethod.
Override the PartCommunicationMainmethod.
Override the GetInitEventArgs method.
Implement the interface event handlers.
Override the RenderWebPartmethod.
Implement supporting methods.
Step 1: Create the interface class
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.
}
Step 2: Declare events
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;
Step 3: Override the EnsureInterfaces method, and then call the RegisterInterface method
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)
Note
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.
Note
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
Note
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.
Step 4: Override the CanRunAt method
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;
}
Step 5: Override the PartCommunicationConnect method
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++;
}
}
Step 6: Override the PartCommunicationInit method
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
Note
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);
}
}
}
Step 7: Override the PartCommunicationMain method
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
Note
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);
}
}
}
Step 8: Override the GetInitEventArgs method
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
Note
This method can be implemented on the server or client.
Important
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);
}
}
Step 9: Implement the interface event handlers
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.
}
Step 10: Override the RenderWebPart method
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,
}
}
}
Step 11: Implement supporting methods
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
}
A Pair of Sample Web Parts that Implement the ICellProvider and ICellConsumer Interfaces
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
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.
After importing the sample Web Parts into a Web Part Page, connect the Web Parts:
Click Modify Shared Page (or Modify My Page), and then click Design This Page.
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.
In the Cell Provider Web Part, enter a value into the text box, and then click the Fire CellReady button.