SharePoint 2010’s Social Web Parts and Web templates/Site definitions

In today’s segment of “Things that should work out of the box but don’t”  I’m going to discuss adding any of the social web parts (Tag cloud, Noteboard etc.) to a page/site definition or a web template.

Coming to this I thought it’s going to be as simple as exporting the web part I wish to add (Tag cloud in my case), copy its .webpart file’s content to my pages module’s element.xml file and deploy my lovely solution. Boy was I wrong…

Doing the above I was greeted with the informative error message: “Cannot import this web part“. After double (and triple) checking the XML data I pasted I realized that this isn’t going to work. A quick search on Google revealed the following article from Microsoft itself:

You receive the error “Cannot import this web part” when you try to import an exported TagCloud Web Part in SharePoint 2010” (article link)

To summarize the article, the social web parts are based on Microsoft.SharePoint.WebPartPages.WebPart and not System.Web.UI.WebControls.WebParts.WebPart, and as such, the v3 schema (the .webpart file’s content) that SharePoint exports when you click on Export  is not valid for web parts based on the older namespace (Microsoft.SharePoint.WebPartPages.WebPart). This kind of web parts needs to be exported using the v2 schema, but sadly SharePoint 2010 doesn’t give you this option.jackie-chan-wtf In order to get the v2 schema (a .dwp file) the article suggests you head over to the web part gallery of the site collection and export the web part from there.

Success! doing this exports the web part with the v2 schema and providing the much needed .dwp file. I added the file’s content to my pages module element’s elements.xml file for the page it should appear at and the skies are all smiling and happy again. That is until you try to set ANY type of property of that web part that is specific to it… (i.e. the tag cloud’s scope property). soclose In my particular case, i needed to have the tag cloud web part scoped to “Under the current URL by all users“. No matter what i tried to add to the schema, nothing worked.

Long story short, i decided to handle this change at the code level.

Changing web part properties programmatically:

At the heart of working with web parts programmatically lies the SPLimitedWebPartManager object. From the MSDN documentation for this object we learn that “The SPLimitedWebPartManager provides a limited set of Web Part operations that can be performed in object model scenarios when there is no HttpContext and no instantiated Page object.”

Since we are not going to initiate any page object here, this is perfect for us.

One ‘gotcha’ to note about the SPLimitedWebPartManager object is to always make sure we perform check out on the page we are going to change the web part properties on – before –  we initiate the object!

Checking out the desired page can be done with the following code:

SPList pagesList = web.Lists["Pages"];

SPQuery query = new SPQuery();

query.Query = @”<Where><Eq><FieldRef Name=’LinkFilename’ /><Value Type=’Text’>Default.aspx</Value></Eq></Where>”;

query.ViewFields = “<FieldRef Name=’LinkFilename’ />”;

SPListItemCollection page = pagesList.GetItems(query);

if (page != null)

page[0].File.CheckOut();

Once the page is checked out, we can move forward and initiate the SPLimitedWebPartManager object:

SPLimitedWebPartManager webparts = web.GetLimitedWebPartManager(web.Url + "/Pages/Default.aspx", System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared);

Now that we have the SPLimitedWebPartManager ready, we can loop trough all of the web parts presented in the page, looking for the specific one we need, and change its properties! In my example i will change the scope of a tag cloud web part:

foreach (var wp in webparts.WebParts) {  

if (wp is TagCloudWebPart) {

(wp as TagCloudWebPart).UserScope = TagCloudUserScope.UnderUrlEveryone;

webparts.SaveChanges((wp as TagCloudWebPart));

page[0].File.CheckIn(null);

page[0].File.Publish(null);

break;

}

}

The above code loops trough the WebParts collection of the SPLimitedWebPartManager object and looks for a web part that is of type TagCloudWebPart. Once it finds it it sets it’s user scope property, check in and publish the page that hosts it and breaks the loop.

You can use this method to programatically change properties of any kind of web part you wish, tough i would recommend to use the v3 schema for that where possible. It’s much much easier.

And with this optimistic message we conclude this segment of “Things that should work out of the box but don’t“.

Advertisements