Connecting WebParts programmatically in SharePoint

Let’s start by an example.

Example

In this blog post, I’m going to assume we have a webpart that displays a contact list and another one that displays a map with the possibility to pinpoint an address. To keep things simple I assume the address is merely a string.

public class Map : WebPart
{

}

public ContactList : WebPart
{
    [Personalizable]
    string SelectedAddress { get; set; }
}

To connect these webparts, we typically do the following four steps:

  • Write an interface to contain the information we need to transfer (i.e. Address)
  • Implement the interface in the provider webpart (i.e Map)
  • Write a callback method in the provider webpart to return the address.
  • Write another callback method in the consumer webpart to receive the address.
public interface IAddressConnection {
    string SelectedAddress { get; set; }
}

public class Map : WebPart
{
    [ConnectionConsumer("Pinpoint address", "Address")]
    public void ConsumeAddress(ISelectedAddress address)
    {
        // Set the map extent and display a pinpoint.
    }
}

public ContactList : WebPart, IAddressConnection
{
    [Personalizable]
    public string SelectedAddress { get; set; }

    [ConnectionProvider("Selected address", "Address")]
    public ISelectedAddress ProviderAddress()
    {
        return this;
    }
}

ConnectWebParts()

In order to connect two webparts, you need an instance of each webpart plus the WebPartManager (to be precise the SPLimitedWebPartManager) for the page they are hosted in and of course you need to know which of their connection points you are going to connect.

Let’s say you already have the WebPartManager and the two webparts at hand. In that case you can use the following method. Note that T is the interface these two webparts share.

public void ConnectWebParts(WebPartManager webPartManager, WebPart consumer, WebPart provider)
{
    var consumerConnection =
        webPartManager.GetConsumerConnectionPoints(consumer)
            .Cast<ConsumerConnectionPoint>()
            .FirstOrDefault(c => c.InterfaceType == typeof(T));
    var providerConnection =
        webPartManager.GetProviderConnectionPoints(provider)
            .Cast<ProviderConnectionPoint>()
            .FirstOrDefault(c => c.InterfaceType == typeof(T));
    webPartManager.ConnectWebParts(provider, providerConnection, consumer, consumerConnection);
}

The above method assumes that these webpart only have one connection point of type T, which makes sense most of the time, but in case your webpart have multiple connection points of the same interface.

By using ConnectWebParts method, we can easily connect the Map to the Contacts webpart.

ConnectWebParts<IAddressConnection>(webPartManager, map, contacts)

But, how to get the WebPartManager and instances of the webparts? you might ask. These webparts might be used in any page, but you definitely know on which page you are going to connect them. By having a reference to the page you can instantiate a WebPartManager and with that you can find you webparts too. If you are doing this in the code-behind of the page or a control (or webpart) in the page, you can do as following:

var webPartManager = WebPartManager.GetCurrentWebPartManager(this) // or this.Page if we are in a control.
var consumer =
    webPartManager.WebParts.Cast<WebPart>()
        .FirstOrDefault(w => w.GetType() == typeof(Map));
var provider =
    webPartManager.WebParts.Cast<WebPart>()
        .FirstOrDefault(w => w.GetType() == typeof(Contacts));
ConnectWebParts<IAddressConnection>(webPartManager, consumer, provider)

What if the code is not running in the page? Then you need to get an instance of the page. Let’s use SPLimitedWebPartManager this time.

using (var site = new SPSite("http://mydomain/mysite"))
{
    var file = site.RootWeb.GetFile("myfolder/mypage.aspx");
    var webPartManager = file.GetLimitedWebPartManager(PersonalizationScope.Shared);
    var consumer =
        webPartManager.WebParts.Cast<WebPart>()
            .FirstOrDefault(w => w.GetType() == typeof(Map));
    var provider =
        webPartManager.WebParts.Cast<WebPart>()
            .FirstOrDefault(w => w.GetType() == typeof(Contacts));
    ConnectWebParts<IAddressConnection>(webPartManager, consumer, provider)
}

Please note that you might need to checkout the page, publish and approve it if versioning or approval workflow has been enabled on the library that contains the page.

I hope you find it useful. By the way, don’t forget the null checks!

Connecting WebParts programmatically in SharePoint