Using the SharePoint 2010 Client Object Model - Part 6

Time to wrap up this series and we’re going to mostly talk about managing web parts using the client object model.  First, however, we’re going to take a quick peek at something else you can do, which is create additional Edit Control Block (ECB) menu items.  Yes, you can even create ECB items from the client OM.  Here’s how we do that:

//get the connection

ClientContext ctx = new ClientContext("https://foo");

 

//get the list

List theList = ctx.Web.Lists.GetByTitle("My List Title");

 

//load the custom actions collection

ctx.Load(theList.UserCustomActions);

ctx.ExecuteQuery();

               

//*****************************************************

//here’s one way of finding a menu item and deleting it

foreach (UserCustomAction uca in theList.UserCustomActions)

{

if (uca.Title == "My New Menu")

      {

      uca.DeleteObject();

            break;

      }

}

//*****************************************************

 

//create the custom action

UserCustomAction act = theList.UserCustomActions.Add();

 

//set the properties and update

act.Location = "EditControlBlock";

act.Sequence = 100;

act.Title = "My New Menu";

act.Url = "/_layouts/settings.aspx";

act.ImageUrl = "/_layouts/images/availableworkflow.gif";

act.Update();

 

//execute the query to add everything

ctx.ExecuteQuery();

There you have it.  Navigate to the site, click to get the ECB menu and you should see your new menu item with the icon you specified for the ImageUrl.  Note that you can also use this same methodology to place an item on the Site Actions menu.  The differences are:

1) Instead of getting the UserCustomActions collection from a list, get it from the Web

2) Instead of the location being “EditControlBlock”, it should be “Microsoft.SharePoint.StandardMenu”

3) You need to set the Group property to “SiteActions”

Try it out and you’ll see it works pretty well.  Now, when we start working with web parts we have one class that probably looks pretty familiar and one new methodology that we haven’t seen yet.  The familiar class is the LimitedWebPartManager, which is the same class that was used in SharePoint 2007 to manage the web parts on a page.  The new methodology is the way in which we get access to the LimitedWebPartManager class – we’re going to do that through the File class in the client object model.  The pattern will start out in the same familiar way – we’ll get our ClientContext.  Next though we’ll instantiate our File class object using the relative path to a web part page.  In a publishing site that will typically be something like “/pages/default.aspx”.  For one of the new team sites it will be something like “/SitePages/Home.aspx”.

Once we have a reference to the web part page, then we can get an instance of the LimitedWebPartManager class and start working with web parts on the page in much the same way we did in SharePoint 2007.   Here’s how that code might look when working with a team site home page:

//get the connection

ClientContext ctx = new ClientContext("https://foo");

 

//get the home page

File home = ctx.Web.GetFileByServerRelativeUrl("/SitePages/home.aspx");

 

//get the web part manager

LimitedWebPartManager wpm =

      home.GetLimitedWebPartManager(PersonalizationScope.Shared);

 

IEnumerable<WebPartDefinition> wpds = null;

 

//create the LINQ query to get the web parts from

//the web part definition collection

wpds = ctx.LoadQuery(

wpm.WebParts.Include(

      wp => wp.Id,

      wp => wp.WebPart));

 

//load the list of web parts

ctx.ExecuteQuery();

 

//enumerate the results

if (wpds.Count() == 0)

//no web parts found on this page

else

{

foreach (WebPartDefinition wpd in wpds)

{

//do something with the web part definition,

                  //or the web part via its WebPart property

            }

}

That’s how we can enumerate through all of the web parts on any web part page.  Now let’s suppose that we want to change a property on the web part.  We use a similar pattern to what has been demonstrated in the earlier posts in this series.  We can get it by Id and then work with it.  Here’s an example of doing that to change the Title property of the part.  Note that the code below includes a checkout and checkin.  It obviously isn’t usually necessary for a team site but is for a publishing site.  If you’re not sure, you can call checkin and checkout and it won’t hurt if the list doesn’t require it.

//get the connection

ClientContext ctx = new ClientContext("https://foo");

 

//get the home page

File home = ctx.Web.GetFileByServerRelativeUrl("/SitePages/home.aspx");

 

//get the web part manager

LimitedWebPartManager wpm =

      home.GetLimitedWebPartManager(PersonalizationScope.Shared);

 

//load the web part definitions

ctx.Load(wpm.WebParts);

ctx.ExecuteQuery();

 

//checkout in case it's needed; doesn't hurt if it doesn't

home.CheckOut();

 

//get the web part definition

WebPartDefinition wpd =

      wpm.WebParts.GetById(MyWebPartId);

 

//set the title

wpd.WebPart.Title = "My Web Part Title";

 

//save changes

wpd.SaveWebPartChanges();

 

//checkin in case it's needed; doesn't hurt if it doesn't

home.CheckIn(string.Empty, CheckinType.MajorCheckIn);

 

//execute the query to save changes

ctx.ExecuteQuery();

Okay, now for my final trick we’ll look at how to add and delete web parts from a page.  To add a web part I’m going to wimp out a little and just show an example of adding a web part by using a chunk of Xml.  You can obviously do it other ways, such as providing the assembly and class as well.  You would do that by creating a new instance of the WebPart class and then using the LimitedWebPartManager to add it to the page.  This is essentially the same process I covered for SharePoint 2007 in my blog posting about customizing My Sites, which you can find at https://blogs.msdn.com/sharepoint/archive/2007/03/22/customizing-moss-2007-my-sites-within-the-enterprise.aspx.  As a side note this process will be much easier in SharePoint 2010 by using the new site created event.  But I digress; here’s the code to add a web part to a page using a chunk of Xml:

//get the connection

ClientContext ctx = new ClientContext("https://foo");

 

//get the home page

File home = ctx.Web.GetFileByServerRelativeUrl("/SitePages/home.aspx");

 

//checkout in case it's needed; doesn't hurt if it doesn't

home.CheckOut();

 

//get the web part manager

LimitedWebPartManager wpm =

      home.GetLimitedWebPartManager(PersonalizationScope.Shared);

 

string webPartXml =

                "<?xml version=\"1.0\" encoding=\"utf-8\"?><WebPart xmlns:xsi=\"https://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"https://www.w3.org/2001/XMLSchema\" xmlns=\"https://schemas.microsoft.com/WebPart/v2\"> <Title>My test web part</Title> <FrameType>Default</FrameType> <Description>Use for formatted text, tables, and images.</Description> <IsIncluded>true</IsIncluded> <ZoneID>Header</ZoneID> <PartOrder>0</PartOrder> <FrameState>Normal</FrameState> <Height /> <Width /> <AllowRemove>true</AllowRemove> <AllowZoneChange>true</AllowZoneChange> <AllowMinimize>true</AllowMinimize> <AllowConnect>true</AllowConnect> <AllowEdit>true</AllowEdit> <AllowHide>true</AllowHide> <IsVisible>true</IsVisible> <DetailLink /> <HelpLink /> <HelpMode>Modeless</HelpMode> <Dir>Default</Dir> <PartImageSmall /> <MissingAssembly>Cannot import this Web Part.</MissingAssembly> <PartImageLarge>/_layouts/images/mscontl.gif</PartImageLarge> <IsIncludedFilter /> <Assembly>Microsoft.SharePoint, Version=13.0.0.0, Culture=neutral, PublicKeyToken=94de0004b6e3fcc5</Assembly> <TypeName>Microsoft.SharePoint.WebPartPages.ContentEditorWebPart</TypeName> <ContentLink xmlns=\"https://schemas.microsoft.com/WebPart/v2/ContentEditor\" /> <Content xmlns=\"https://schemas.microsoft.com/WebPart/v2/ContentEditor\"><![CDATA[This is my test text! <DIV>&nbsp;</DIV><DIV>Blah blah blah</DIV><DIV>&nbsp;</DIV><DIV>And another blah</DIV>]]></Content> <PartStorage xmlns=\"https://schemas.microsoft.com/WebPart/v2/ContentEditor\" /></WebPart>";

 

//create the web part definition

WebPartDefinition newWpd = wpm.ImportWebPart(webPartXml);

 

//add the web part

wpm.AddWebPart(newWpd.WebPart, "Left", 1);

               

//checkin in case it's needed; doesn't hurt if it doesn't

home.CheckIn(string.Empty, CheckinType.MajorCheckIn);

 

//execute the query to add everything

ctx.ExecuteQuery();

And now, we delete a web part from the page:

//get the connection

ClientContext ctx = new ClientContext("https://foo");

 

//get the home page

File home = ctx.Web.GetFileByServerRelativeUrl("/SitePages/home.aspx");

 

//checkout in case it's needed; doesn't hurt if it doesn't

home.CheckOut();

 

//get the web part manager

LimitedWebPartManager wpm =

      home.GetLimitedWebPartManager(PersonalizationScope.Shared);

 

//load the web part definitions

ctx.Load(wpm.WebParts);

ctx.ExecuteQuery();

 

//get the web part

WebPartDefinition wpd = wpm.WebParts.GetById(MyWebPartId);

 

//delete the part

wpd.DeleteWebPart();

 

//checkin in case it's needed; doesn't hurt if it doesn't

home.CheckIn(string.Empty, CheckinType.MajorCheckIn);

 

//execute the query to do the deletion

ctx.ExecuteQuery();

There you go folks, a pretty good run through the different features of the client object model. Hopefully you can appreciate now all of functionality this new set of classes provides, and it instills happy happy joy joy feelings in SharePoint developers everywhere. I hope you found this series useful and can start writing some killer client object model applications out there. I had a lot of fun putting this together and hope you enjoyed it too.