Module 8 - Code Snippets: Creating Silverlight User Interfaces for SharePoint 2010 Solutions

The following code shows how to use the SharePoint client object model in a Silverlight application. The code performs the following actions in the Silverlight application:
  - Obtains a reference to the current SharePoint site in the application's APP.XAML file
  - Updates a progress bar and status label in real time, based on accessing and retrieving data from SharePoint
  - Renders media files (images and videos) from SharePoint in the Silverlight application

Note: Silverlight code must call methods of the client object model asynchronously, so that the main UI thread in Silverlight is not blocked while waiting for responses from SharePoint. In this way, the progress bar (and status label) can be updated appropriately. However, because the results from SharePoint are returned on background threads (becuase of the asynchronous nature of the calls) and because updating the UI must be performed back on the main UI thread, the code switches back to the main UI thread by using the Dispatcher.BeginInvoke() calls that you can see below.

Also note that the code relies on there being the following controls in the Silverlight User Control:
  - A Silverlight ProgressBar named Loader
  - A Silverlight TextBlock named Status
  - A Silverlight StackPanel named MyContainer 

// The following using statements are in the application file (APP.XAML.CS)
using Microsoft.SharePoint.Client;
using System.Threading;

//The following line of code is in the Startup event for the
//Silverlight application in the application file (APP.XAML.CS)
ApplicationContext.Init (e.InitParams, SynchronizationContext.Current);

//The following using statements are in a Silverlight user control
using Microsoft.SharePoint.Client;
using System.Threading;

//The following code is in a Silverlight user control
ClientContext clientCtx;
Microsoft.SharePoint.Client.List docs;
int fileTracker = 0;
int rowTracker = 0;

private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{

Loader.Maximum = 3;
Loader.Value = 0;
Status.Text = "Connecting to Web...";
clientCtx = new ClientContext(ApplicationContext.Current.Url);
clientCtx.Load(clientCtx.Web);
clientCtx.ExecuteQueryAsync(updateConnectionStatus, null);
}
void updateConnectionStatus(Object sender, ClientRequestSucceededEventArgs e)
{
//This method starts on a background thread, but needs to update the progress bar and label in the UI
//Therefore, it calls Dispatcher.BeginInvoke() to perform the UI updating on the main thread
Dispatcher.BeginInvoke(makeProgressWebConnection);
}
void makeProgressWebConnection()
{
//Called by Dispatcher.BeginInvoke() in the function above
//The code is now running back on the main UI thread, and so can update the UI
Loader.Value++;
Status.Text = "Web Connected. Connecting to Lists...";
clientCtx.Load(clientCtx.Web.Lists);
clientCtx.ExecuteQueryAsync(updateListStatus, null);
}
void updateListStatus(Object sender, ClientRequestSucceededEventArgs e)
{
//This method starts on a background thread, but needs to update the progress bar and label in the UI
//Therefore, it calls Dispatcher.BeginInvoke() to perform the UI updating on the main thread
Dispatcher.BeginInvoke(makeProgressListConnection);
}
void makeProgressListConnection()
{
//Called by Dispatcher.BeginInvoke() in the function above
//The code is now running back on the main UI thread, and so can update the UI
Loader.Value++;
Status.Text = "Lists Connected. Getting List data...";
MyContainer.Children.Clear();
docs = clientCtx.Web.Lists.GetByTitle("Shared Documents");
clientCtx.Load(docs);
clientCtx.Load(docs.RootFolder);
clientCtx.Load (docs.RootFolder.Files);
clientCtx.ExecuteQueryAsync(getListData, null);
}
void getListData(Object sender, ClientRequestSucceededEventArgs e)
{
//This method starts on a background thread, but needs to update the progress bar and label in the UI
//Therefore, it calls Dispatcher.BeginInvoke() to perform the UI updating on the main thread
Dispatcher.BeginInvoke(loadFiles);
}
private void loadFiles()
{
//Called by Dispatcher.BeginInvoke() in the function above
//The code is now running back on the main UI thread, and so can update the UI
Loader.Maximum = docs.RootFolder.Files.Count;
Loader.Value = 0;
Status.Text = "Loading Files...";
fileTracker = 0;
foreach (File fle in docs.RootFolder.Files)
{
clientCtx.Load(fle);
clientCtx.ExecuteQueryAsync(addFileToUI, null);
}
}
void addFileToUI(Object sender, ClientRequestSucceededEventArgs e)
{
//This method starts on a background thread, but needs to update the progress bar and label in the UI
//It can now also render the files, which is another UI operation
//Therefore, it calls Dispatcher.BeginInvoke() to perform the UI updating on the main thread
Dispatcher.BeginInvoke(addFile);
}

StackPanel row = new StackPanel();
void addFile()
{
//Called by Dispatcher.BeginInvoke() in the function above
//The code is now running back on the main UI thread, and so can update the UI
string fName = docs.RootFolder.Files[fileTracker].Name;
string fUrl = docs.RootFolder.Files[fileTracker].ServerRelativeUrl;
fUrl = clientCtx.Url + fUrl;
//Simple logic to lay out the files in a three-column configuration
if ((rowTracker % 3) == 0)
{
row = new StackPanel();
row.Orientation = Orientation.Horizontal;
MyContainer.Children.Add(row);
}
if ((fName.EndsWith(".png")) || (fName.EndsWith(".jpg")))
{
Image img = new Image();
img.MaxWidth = 100;
img.Stretch = Stretch.Uniform;
BitmapImage bitMap = new BitmapImage(new Uri(fUrl, UriKind.Absolute));
img.Source = bitMap;
HyperlinkButton mediaButton = new HyperlinkButton();
mediaButton.Margin = new Thickness(5);
mediaButton.Content = img;
mediaButton.TargetName = "_blank";
mediaButton.NavigateUri = new Uri(fUrl);
mediaButton.Cursor = Cursors.Hand;
row.Children.Add(mediaButton);
rowTracker++;
}
if (fName.EndsWith(".wmv"))
{
MediaElement media = new MediaElement();
media.MaxWidth = 100;
media.Stretch = Stretch.Uniform;
media.Source = new Uri(fUrl, UriKind.Absolute);
media.AutoPlay = true;
HyperlinkButton mediaButton = new HyperlinkButton();
mediaButton.Margin = new Thickness(5);
mediaButton.Content = media;
mediaButton.TargetName = "_blank";
mediaButton.NavigateUri = new Uri(fUrl);
mediaButton.Cursor = Cursors.Hand;
row.Children.Add(mediaButton);
rowTracker++;
}
Loader.Value++;
fileTracker++;
if (fileTracker >= docs.RootFolder.Files.Count)
{
Status.Text = "All files have now been loaded";
}
}

Comments

  • Anonymous
    November 29, 2009
    Can I access SharePoint services using client object model from a Silverlight application that does not host inside the SharePoint? I guess I need add cross domain access file to SharePoint site. But where shall I put it? Is it in ClientBin or ISAPI folder? Tanks

  • Anonymous
    November 29, 2009
    Hi Andrew Can you please advice how to access SharePoint services using Client object model from Silverlight app that does not host inside SharePoint? I guess I need to add cross domain access policy file. But where shall I put it? Is it in ClientBin or ISAPI folder? Regards Joe Lee

  • Anonymous
    November 29, 2009
    Hi Andrew Here is one more question regarding to Silverligt. If I decide to use Siverlight rather than WebPart, I do not have the option to use Linq to SharePoint. Is that correct?