1
votes

I've implemented 2 webparts (deriving from Microsoft.SharePoint.WebPartPages.WebPart, the WSS 3 WebPart), one of which is a provider and the other the consumer (implementing ASP.net connection model, with ConnectionProviderAttribute and ConnectionConsumerAttribute methods).

I managed to deploy them in a feature which also deploys a Page Layout containing two webpart zones, which are themselves populated during the FeatureAvtivated method of the feature receiver, with the 2 newly created webparts. All of this works just fine.

For information, I used this link to make it work. Beware, the method using AllUsersWebPart tag in elements.xml, shown in links like this one (http://www.andrewconnell.com/blog/archive/2007/10/07/Having-Default-Web-Parts-in-new-Pages-Based-Off-Page.aspx) work, but if you deactivate, then reactivate your feature, you just have double webparts in your future pages based on the layout. The method described here (http://sharepoint.coultress.com/2008/06/adding-web-part-to-page-layout.html) just threw me an error when analysing metadata for the layout aspx file (the problem seemed to come from the line in the ZoneTemplate tag).

My next goal is to connect these webparts together right after all this, thus enabling the end user to create pages, based on the layout, containing by default the two webparts connected together (right now everything works except for the connected part).

I tried something like this, using ASP.net connection model (the other one, WSS model, throws logically an error because I'm not implementing the good interfaces). But even though the connection resulting from the "mgr.SPConnectWebParts()" method doesn't throw any exception and actually adds the connection to the connection list of the webpart manager, I can see in debug mode that the connection property 'IsActive" is false (maybe normal), and that when I create a new page based on the layout, the webparts appear not connected.

Any guess? I believe there's something with the fact that the webparts cannot be connected before the page containing them is actually created, but I'm far from sure of it.

3

3 Answers

2
votes

Declarative web part connection provisioning is actually quite straightforward:

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Module Name="Module1">
    <File Path="Module1\default.aspx" Url="demo.aspx">
      <AllUsersWebPart ID="testProvider">...</AllUsersWebPart>
      <AllUsersWebPart ID="testConsumer">...</AllUsersWebPart>
      <WebPartConnection ID="testConnection"
                         ProviderID="testProvider"
                         ProviderConnectionPointID="providerID"
                         ConsumerID="testConsumer"
                         ConsumerConnectionPointID="consumerID" />
     </File>
  </Module>
</Elements>

Details: http://blogs.code-counsel.net/Wouter/Lists/Posts/Post.aspx?ID=161

You can find connection point IDs with PowerShell if you first connect your web parts manually:

$web = Get-SPWeb <WebURL>
$wpman = $web.GetLimitedWebPartManager("<PageURL>", [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared)
$wpman.SPWebPartConnections
0
votes

Tried creating the web parts on the page programmatically? You'll have far fewer headaches than trying to do it declaratively.

Look up the SPLimitedWebPartManager class for how to handle web parts on a provisioned page.

Also, web parts in a web part zone are tied to the URL of the page on which they are added. This is by design of the the ASP.NET Web Part Manager.

Thus, if you added web parts to zones on a page layout at directory: http://webapp/sites/site/_catalog/master/mypagelayout.aspx - the web parts will ONLY appear on that page. Createa new page at /sites/site/Pages/MyPage.aspx and the web parts you added before won't appear. The workaround for this is to explicitly add web parts not within web part zones, and this can only be done in an authored page layout (usually in SharePoint Designer).

If the web parts are static in the page layout (and you want them to show in every page) then this is actually easier for you to deploy - just maintain the layout in your source, and have it provisioned via a Module element.

0
votes

Finally I used another approach to reach my goal. In the OnLoad event of the provider webpart, I check if my page is in edit/new mode, and then check if the page contains the consumer webpart (via the webpartmanager) and if they are not already connected. If this is the case, I connect them.

The code to connect permanently the webparts:

private void SetUpConnections()
{
    SPSecurity.RunWithElevatedPrivileges(delegate() {
        using (SPSite siteContext = new SPSite(SPContext.Current.Site.ID))
        using (SPWeb webContext = siteContext.OpenWeb(siteContext.ServerRelativeUrl))
        using (SPLimitedWebPartManager spManager = webContext.GetFile(SPContext.Current.File.Url).GetLimitedWebPartManager(PersonalizationScope.Shared))
        {
            foreach (Microsoft.SharePoint.WebPartPages.WebPart consumer in spManager.WebParts)
            {
                if (consumer is MyConsumerWebPart)
                {
                    bool alreadyConnected = false;
                    Microsoft.SharePoint.WebPartPages.WebPart provider = spManager.WebParts[this.ID] as Microsoft.SharePoint.WebPartPages.WebPart;
                    foreach (SPWebPartConnection connection in spManager.SPWebPartConnections)
                    {
                        if (connection.Provider == provider && connection.Consumer == consumer) { alreadyConnected = true; break; }
                    }
                    if (!alreadyConnected)
                    {
                        // Connects webparts permanently (but the page would need a reload to display the connection)
                        ProviderConnectionPoint providerConnectionPoint = spManager.GetProviderConnectionPoints(provider)["MyConnectionProviderInterfaceId"];
                        ConsumerConnectionPoint consumerConnectionPoint = spManager.GetConsumerConnectionPoints(consumer)["MyConnectionConsumerInterfaceId"];
                        spManager.SPConnectWebParts(provider, providerConnectionPoint, consumer, consumerConnectionPoint);

                        // Connects webparts locally (for current edit mode)
                        SPWebPartManager currentSPManager = WebPartManager.GetCurrentWebPartManager(this.Page) as SPWebPartManager;
                        System.Web.UI.WebControls.WebParts.WebPart currentProvider = this;
                        System.Web.UI.WebControls.WebParts.WebPart currentConsumer = currentSPManager.WebParts[consumer.ID];
                        ProviderConnectionPoint currentProviderConnectionPoint = currentSPManager.GetProviderConnectionPoints(currentProvider)["SearchBarProvider"];
                        ConsumerConnectionPoint currentConsumerConnectionPoint = currentSPManager.GetConsumerConnectionPoints(currentConsumer)["SearchBarConsumer"];
                        currentSPManager.SPConnectWebParts(currentProvider, currentProviderConnectionPoint, currentConsumer, currentConsumerConnectionPoint);
                    }
                }
            }
        }
    });
}

The code to check if the page is in new/edit mode:

if (SPContext.Current.FormContext.FormMode == SPControlMode.New
    || SPContext.Current.FormContext.FormMode == SPControlMode.Edit)
{
    this.SetUpConnections();
}