Você está na página 1de 13


true none Brow se

False 0xEEABC39037C

Brow se


/w EPDw UBMA9k


Developing a Silverlight 3.0 Web part for SharePoint 2010

Its been a while since Ive been able to work with Silverlight. I did quite a bit of work about a year ago and blogged about my experiences (here is one of the posts). With SharePoint 2010 development from Silverlight gets much easier. Not only do we have all the Silverlight plumbing automatically in place on the web front end, but there is also a Silverlight web part wrapper that we can use to to easily point to our .xap file. Not only is it easier, its also much more powerful. In this article, I will walk through the Silverlight client object model, one of the three client object models that Microsoft ships for SharePoint 2010. The goal of this post is to demonstrate how this works by creating a simple Silverlight app that does a multiple-file check out. This application will be written in Visual Studio 2010 which also has built-in project types for Silverlight. We start by creating a new C# Silverlight project as shown here.

After you name the project and click OK, youre prompted to create a web project to host it. Since this will be integrating directly with SharePoint, Ill not do this.

For the Silverlight project, add two references that allows us to work with the Silverlight client object model. These are the Microsoft.SharePoint.Client.Silverlight.dll and Microsoft.SharePoint.Client.Silverlight.Runtime.dll assemblies. Both of these can be found in the 14\TEMPLATE\LAYOUTS\ClientBin folder. Open up the MainPage.xaml file and drag and drop a List box control from the toolbox onto the design canvas. For the listbox, set the SelectionMode property to multiple. This will hold our list of files. For my example, I will name my control lstFiles. Now add a button beneath the list box. Set the Content property (the label for the button) to Check Out. Heres what your design editor should looks like

Create a new method for the Loaded event on the LayoutRoot object (this is the grid that is nested inside the Silverlight user control). To do this, first click the Grid element in the XAML markup. In the Properties panel, click the Events button and double click in the Loaded event drop down. This will create the event handler and take you to the code behind page. Add this using clause at the top using SP=Microsoft.SharePoint.Client;

We prefix it with SP to avoid some object name conflicts. In the partial class for MainPage, lets create these class -level variables. //class variables SP.ClientContext context; SP.Web myWeb; SP.List myList; SP.ListItemCollection myItems; List<File> files; In the LayoutRoot_Loaded method, lets initialize our client context. This will provide our entry point and become the object through which all calls to SharePoint are made. Heres the code. context = SP.ClientContext.Current;

By specifying the Current property, we are telling it to take the current SharePoint context. In other words, the web site in which this will be working. Since this will become a web part, we wont know what the Url is so we just have the client object model look it up. Its the same idea as SPContext if youve used that before. Next, lets make a reference to the web site via this line of code. myWeb = context.Web;

You can think of this as acting like the SPWeb object in the server-side object model. And what youll start to see is that the client object model mimics many of the same behaviors that youve used in the server object model. Although, its definitely a subset of the commands, so do not expect a complete duplication. Next, lets get a handle to a document library. In my demo web site, I have a library called Docs where I have loaded a number of files. Here is how I reference it.

//Get handle to document library

myList = myWeb.Lists.GetByTitle("Docs");

Pretty close to the server object model. One difference that you are not referencing the list as a collection. Youll understand why in a minute. Before that, let me prepare a query to return all the files in the library. For this (just as you would have done with the WSS/MOSS object model in the previous version), you can create a CAML query. //Get all files SP.CamlQuery query = new SP.CamlQuery(); query.ViewXml = "<View></View>"; myItems = myList.GetItems(query);

While this is a very simply CAML query, some can be downright ugly. Ive found that it supports the same query capabilities such as ViewFields, Where, OrderBy, etc. At this point, let me make something clear. You you know, the client object model runs on the client, away from the server. To be efficient in its call backs to the server, the design is to batch operations to minimize the number of round trips. In this case, none of the code Ive shown you so far has gone bac k to the server. This is the reason why I cannot reference the Docs library by doing something like myWeb.Lists[Docs] which would be how youd do it in the server object model. To batch these operations up, you can use the Load method on your client context object. //batch up work to do context.Load(myList); context.Load(myItems);

I batch up the list object since I requested a handle to it, and I batch up myItems since I am issuing query on the list. However, still at this point, a call hasnt been made. Thats done with the ExecuteQueryAsync method as you can see next. //execute context.ExecuteQueryAsync(getRequestSucceeded, getRequestFailed);

At this point, the call to the server is made and the batched requests are processed. If all goes well, the

getRequestSucceeded callback delegate is run. If an error occurs, the other one is called. In case youre wondering why I didnt use a synchronous (or blocking) call, its because Silverlight requires all calls to be made asynchronously. This is actually done on a separate thread to prevent the UI from ever locking up. Yes, its more complex, but results in a better user experience. And, isnt that what Silverlight is all about? So, lets first look at the getRequestSucceeded method. Here is the code: private void getRequestSucceeded(object sender, SP.ClientRequestSucceededEventArgs e) { files = new List<File>(); Dispatcher.BeginInvoke(() => { //iterate through each file and add file to our list of files foreach (SP.ListItem item in myItems) { files.Add (new File() {Filepath = item["FileRef"].ToString(), Filename = item["FileLeafRef"].ToString()}); } //bind to listbox lstFiles.DisplayMemberPath = "Filename"; lstFiles.ItemsSource = files; }); }

Let me first clarify what this Dispatcher.BeginInvoke is. As I just mentioned, we are now running on a separate thread. Since we want to process the results and bind them to our listbox, we must do this on the UI thread. The rule to remember: anytime you want to change the UI, you must do it on the UI thread. Ok, so the syntax that were using simply goes to the dispatch er object (the thread that dispatched the currently-running thread), and runs the block of code as an anonymous function. Inside the anonymous function, the code here should be pretty straightforward. We iterate through each item that came back using the foreach statement. We add these into a files object (which is a generic list). The FileRef column is the filepath to the file relative from the web site (e.g. Docs/file1.doc). FileLeafRef is just the filename. From this point, we simply bind this to the

lstFiles, my listbox object. Before I go too much further, let me give you the File class that we use in our generic list. Just add this as a new class to your code behind page. /// <summary> /// Class to hold each file instance /// </summary> public class File { public string Filepath { get; set; } public string Filename { get; set; } }

Next, here is the code that is run if an error occurs. private void checkOutRequestFailed(object sender, SP.ClientRequestFailedEventArgs e) { Dispatcher.BeginInvoke(() => { MessageBox.Show("Error occured: }); } " + e.Message);

Thats enough code to start testing. We still havent implemented the check out, but lets first see if our list of files is populated correctly. As you may already know, the compiled output for a Silverlight application is a .xap file, and this is what SharePoint needs when using the built-in Silverlight web part. So, somehow, we need to get this .xap file referenced in SharePoint. There are lots of options such as manually uploading into a document library, placing it into the 14 hive. However, this is a perfect example of where a sandbox solution would work great. What Ill do is deploy this as a module-type feature and locate it within

the root web of the web site where this feature is activated. Heres how you can do this. Add a new Empty SharePoint project to your current Visual Studio solution. When prompted, make it a sandbox solution which should be the default. For my demo, Ill also set the debug Url to the web site where my Docs library exists as you can see here.

Click Finish and then a new item in this new project. Make it a module type as shown here.

Lets do a little bit of clean up before we add our .xap file as a new file in this module. Start by removing the Sample.txt file. This also automatically removes the <File> entry from the elements manifest file (Elements.xml) for this Feature. This feature file management is part of the new SharePoint tooling in Visual Studio 2010. What we now need to do is reference the .xap file from the Silverlight project as a file in this module. You can do this manually, but theres a great automated way to do this. In the Visual Studio Solution Explorer, click the SilverlightModule node (which was the name of the module I added). In the properties window, click the ellipsis button for the Project Output References. In the dialog, add a new member and set the Project Name to point to the Silverlight project. Set the Deployment type to be Element File. This is shown here.

Click Ok to save. The final step is to simply add the <File> entry into the elements manifest file (Elements.xml). Here is the syntax showing the new line Ive added.

Here is what this means during deployment: the SLApp2.xap file (the filename of my compiled Silverlight application) will be located within the SilverlightModule folder within the WSP package. The Url is where in the web site this will be placed when this feature is activated. Upon activation, SharePoint will copy the .xap file into the root folder of the web site. I could have also stored this into a document library as a ghostable reference as well. At this point, I am going to do a full build of my projects. After this, I will select deploy as shown here.

This should package everything up and deploy it as a sandbox solution into SharePoint. It will then activate the feature in my teamsite web site (http://sp2010a/teamsite). At this point, I just need to go into a web page within this site and add the built-in Silverlight web part. In case you havent seen this before, here is how it looks when adding.

After you add it, it will prompt you for the Url to your .xap file. I will enter in /teamsite/SLApp2.xap which is the path relative from the site collection to the Silverlight application. When all this is done, here is how it looks.

Pretty cool so far. Okay, actually it renders this way below with a messed up title. This, I assume is just a beta 2 bug. To resolve it, I just set the chrome type for the web part to None.

Lets now go back to the Silverlight app and implement our final piece of logic to do the check out. Go to the design page

(MainPage.xaml) and double click on the Check Out button to create an event handler. Here is the code I am using inside the button click event. //iterate through each file selected foreach (File item in lstFiles.SelectedItems) { //batch up file for checkout SP.File f = myWeb.GetFileByServerRelativeUrl(item.Filepath); f.CheckOut(); } //execute context.ExecuteQueryAsync(checkOutRequestSucceeded, checkOutRequestFailed);

This should be easy to follow and very much like the server object model. The only difference is that I need to call the ExecuteQueryAsync again to actually call back to do the work. The final items are the two callback methods when check out completes. Here they are. private void checkOutRequestSucceeded(object sender, SP.ClientRequestSucceededEventArgs e) { Dispatcher.BeginInvoke(() => { MessageBox.Show("Files checked out"); }); }

private void checkOutRequestFailed(object sender, SP.ClientRequestFailedEventArgs e) { Dispatcher.BeginInvoke(() => { MessageBox.Show("Error occured: }); " + e.Message);

Time to recompile and redeploy everything. When re-deploying new versions of Silverlight apps, you need to be careful that the browser does not cache your old version of the application. Ive gotten in the habit of always dumping my browser cache, and I would suggest you do the same. When thats done, refresh the page and test it out.

If we select the Docs library, you can see that these two documents are indeed checked out.

As you can see, performing functions like this are much easier than calling into or creating your own custom web service. You might be wondering what exactly the client object model is doing to perform this task. Well, actually, it is calling a web service. In this case, the client.svc WCF web service that is new in SharePoint 2010. For this example, it is posting a package of XML to the http://sp2010a/teamsite/_vti_bin/client.svc/ProcessQuery function. Here is the XML payload that it is sending. <Request AddExpandoFieldTypeSuffix="true" SchemaVersion="" LibraryVersion="14.0.4536.1000" ApplicationName="Silverlight Library"

xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009"> <Actions> <ObjectPath Id="41" ObjectPathId="40" /> <ObjectIdentityQuery Id="42" ObjectPathId="40" /> <Method Name="CheckOut" Id="43" ObjectPathId="40" /> <ObjectPath Id="45" ObjectPathId="44" /> <ObjectIdentityQuery Id="46" ObjectPathId="44" /> <Method Name="CheckOut" Id="47" ObjectPathId="44" /> </Actions> <ObjectPaths> <Method Id="40" ParentId="3" Name="GetFileByServerRelativeUrl"> <Parameters> <Parameter Type="String">/teamsite/Docs/Coal.docx</Parameter> </Parameters> </Method> <Method Id="44" ParentId="3" Name="GetFileByServerRelativeUrl"> <Parameters> <Parameter Type="String">/teamsite/Docs/ElectricPower.docx</Parameter> </Parameters> </Method> <Property Id="3" ParentId="1" Name="Web" /> <StaticProperty Id="1" TypeId="{3747adcd-a3c3-41b9-bfab-4a64dd2f1e0a}" Name="Current" /> </ObjectPaths> </Request>

This example walked you through the client object for for Silverlight, but remember that there are two other client object models. One is for just regular .NET applications (Windows Forms, WPF, console, etc.) and another one is for JavaScript (i.e. web pages). The one for .NET is very similar to the one youve seen here since both are based on incarnations of the .NET Framework. The JavaScript one is conceptually similar, but its syntax is a bit different.

With that, Ill bring this article to a close. Hopefully you learned a thing or two about the client object model. I also hope youre eager to go out and give it a test drive in your own applications. Have fun!
Posted at 12/18/2009 8:51 AM by System Account | Category: Development | Permalink | Email this Post | Comments (0)

There are no comments yet for this post. Items on this list require content approval. Your submission will not appear in public views until approved by someone with proper rights. More information on content approval.

* *


Posted By

Use this page to add attachments to an item.