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("http://foo");
//get the list
List theList = ctx.Web.Lists.GetByTitle("My List Title");
//load the custom actions collection
//here’s one way of finding a menu item and deleting it
foreach (UserCustomAction uca in theList.UserCustomActions)
if (uca.Title == "My New Menu")
//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";
//execute the query to add everything
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 home page
File home = ctx.Web.GetFileByServerRelativeUrl("/SitePages/home.aspx");
//get the web part manager
LimitedWebPartManager wpm =
IEnumerable<WebPartDefinition> wpds = null;
//create the LINQ query to get the web parts from
//the web part definition collection
wpds = ctx.LoadQuery(
wp => wp.Id,
wp => wp.WebPart));
//load the list of web parts
//enumerate the results
if (wpds.Count() == 0)
//no web parts found on this page
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.
//load the web part definitions
//checkout in case it's needed; doesn't hurt if it doesn't
//get the web part definition
WebPartDefinition wpd =
//set the title
wpd.WebPart.Title = "My Web Part Title";
//checkin in case it's needed; doesn't hurt if it doesn't
//execute the query to save changes
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 http://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:
string webPartXml =
"<?xml version=\"1.0\" encoding=\"utf-8\"?><WebPart xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns=\"http://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=188.8.131.52, Culture=neutral, PublicKeyToken=94de0004b6e3fcc5</Assembly> <TypeName>Microsoft.SharePoint.WebPartPages.ContentEditorWebPart</TypeName> <ContentLink xmlns=\"http://schemas.microsoft.com/WebPart/v2/ContentEditor\" /> <Content xmlns=\"http://schemas.microsoft.com/WebPart/v2/ContentEditor\"><![CDATA[This is my test text! <DIV> </DIV><DIV>Blah blah blah</DIV><DIV> </DIV><DIV>And another blah</DIV>]]></Content> <PartStorage xmlns=\"http://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);
And now, we delete a web part from the page:
//get the web part
WebPartDefinition wpd = wpm.WebParts.GetById(MyWebPartId);
//delete the part
//execute the query to do the deletion
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.
Microsoft finally got around to fixing a design flaw. Sharepoint is nothing more than a meta-database plan and simple. All the application development effort inside the Sharepoint environment was MADNESS from the start.
ASP.NET is a great application and WCF is great for offering services. These interfaces where always there as web services and it just took some imagination to place an object model over it. I would never do development inside of Sharepoint unless is was an admin tool.
Microsoft finally caught up to proper design after all this time and angst. But are the going to release the Client Object Model code so that you can port it to interface from disparate client? My guess is no. Which means I'll have to still use the raw Web Services and construct my own client object model.
There are many more clients these days that are running on OS's other than Windows.
Great series of articles. Would you consider doing one about Surveys? Getting a list of survey questions, submitting a survey, finding out if the survey allows multiple responses, if the current user has already submitted a response, etc.
Great article. But I was wondering if there is any way to access custom properties of a webpart. The webpart is not bound to any underlying list item and the content are inline custom properties. Is it possible to access the values of those properties using COM?
Great series...some important know-hows were explained with examples...Looking forward to this for more updates.Thanks :)