Using Infragistics Components for SharePoint Data in Silverlight Applications

 

Today developers often need to use data from SharePoint in their applications.

When talking about Silverlight and SharePoint data we have two cases:

  • Silverlight application in the context of SharePoint (as a part of ASP.Net Web Part).
  • Silverlight application outside the context of SharePoint (such as blankets application that simply accesses SharePoint data).

This post is about the second approach (Silverlight application outside the context of SharePoint). Often in today's Line of Business applications applications access the SharePoint sites, and other resources in them as lists and libraries.

In general developers could use several data access technologies to maintain SharePoint data:

  • SharePoint web Services
  • Silverlight Client Object Model
  • Data Services Client Model
  • OWSSRV.DLL (The ISAPI extension that implements SharePoint Team Services functionality)

 

Understanding the Client Object Model

The Client Object Model fundamentally is a new Windows Communication Foundation (WCF) SharePoint service called Client.svc and three proxies: .NET CLR, Silverlight, and JavaScript. You program against the client proxies just as you do with any service. Calls to and from the server are sent in batches to increase network efficiency.

SPAccessSl_Pic09a[1]

The Client Object Model is really three separate object models, one for the .NET CLR, one for Silverlight, and one for JavaScript. The .NET CLR version is used to create applications such as WinForms, Windows Presentation Foundation (WPF), and console applications, as well as PowerShell scripts. The Silverlight version works with both in-browser and out-of-browser Silverlight applications. The JavaScript version enables your Ajax and jQuery code to call back to SharePoint.

SharePoint 2010 ships with Silverlight Object Model that simplifies working with SharePoint data within Silverlight components. Thanks to the new object model you no longer have to create and deploy custom services to retrieve data from SharePoint. Out of the box the Silverlight Object Model encapsulates calling standard SharePoint WCF Services which makes it extremely easy for you as a developer to create Silverlight components that communicate with SharePoint. Although working with the Silverlight Object Model is pretty easy, there is one thing that you have to keep in mind while developing for anonymous users.

In this article, we will see how to use the Silverlight Client Object Model with SharePoint 2010 data and how visualize this data with Infragistics Silverlight components (XamGrid and XamDataTree).

 

Prerequisites

1. Client side:

 

2. Server side:

  • SharePoint Foundation 2010 or a higher license
  • SharePoint settings:
  • User credentials. Silverlight applications runs under user rights. We should have for these users permissions in SharePoint
  • ClientAccessPolicy.xml

If you need to use cross domain calls (Silverlight application is running in your domain but calling a service on other domain) then you must have to use clientaccesspolicy.xml file. Because, cross domain communication requires protection against multiple security threats. To elaborate a little, let assume that your Silverlight application is running on http://abcintranet.com/som and this application is trying to call a service on http://xyzintranet.com/pom/service.svc. This request will be prevented as there may be malicious Silverlight controls which are trying to perform an unauthorized operation by calling the service. Silverlight 4 supports two kinds of policy files for cross domain access: Place a ClientAccessPolicy.xml file at the root location of the domain where the service is hosted to configure the service to allow cross-domain access. Place a CrossDomain.xml file at the root location of the domain where the service is hosted. The file must mark the entire domain as public. In our case, we have to add a ClientAccessPolicy.xml file at the root location of the domain. Create the file with the following xml:

   1: <?xml version="1.0" encoding="utf-8" ?>  
   2: <access-policy>   
   3:       <cross-domain-access>
   4:             <policy>       
   5:                   <allow-from http-request-headers="*">
   6:                          <domain uri="*" /> 
   7:                   </allow-from>
   8:                   <grant-to>
   9:                          <resource path="/" include-subpaths="true" /> 
  10:                   </grant-to>
  11:            </policy>
  12:      </cross-domain-access>
  13: </access-policy>

 

  • Anonymous user credentials for some methods

Silverlight Object Model uses anonymous users to access SharePoint data. Unfortunately SharePoint needs to remove restrictions on some methods, called under anonymous user from Client Object Model API. Here you could find the the solution : http://blog.mastykarz.nl/inconvenient-silverlight-object-model-anonymous-users/

SPAccessSl_Pic04[3]

GetItems method has been enabled by the administrator

Preparations:

Lets create a Silverlight project and add a few references to the following libraries:

  • Microsoft.SharePoint.Client.Silverlight.dll.
  • Microsoft.SharePoint.Client.Silverlight.Runtime.dll.

You can find these APIs under: “C:\Program Files\Common Files\Microsoft Shared\SharePoint Client\”

SPAccessSl_Pic01[1]

Add a references to NetAdvantage for Silverlight libraries:

  • InfragisticsSL5.v11.2.dll
  • InfragisticsSL5.Controls.Grids.XamGrid.v11.2.dll
  • InfragisticsSL5.Controls.Menus.XamDataTree.v11.2.dll

SPAccessSl_Pic02[1]

 

Add in the main Silverlight page Infragistics XamGrid and XamDataTree. Silverlight Data Tree is used do display all SharePoint items in specified URL. Infragistics Silverlight Grid is used to display items from a specific SharePoint list.

SPAccessSl_Pic03[1] 

   1: <Grid>
   2:      <Grid.ColumnDefinitions>
   3:          <ColumnDefinition Width="400"/>
   4:          <ColumnDefinition/>
   5:      </Grid.ColumnDefinitions>
   6:      <ig:XamDataTree x:Name="xamSpListTree" NodeLineVisibility="Visible" ActiveNodeChanged="XamSpListTreeActiveNodeChanged">
   7:          <ig:XamDataTree.SelectionSettings>
   8:              <ig:TreeSelectionSettings NodeSelection="Single" />
   9:          </ig:XamDataTree.SelectionSettings>
  10:          <ig:XamDataTree.ExpandedIconTemplate>
  11:              <DataTemplate>
  12:                  <Image Source="/AccessSharePoint;component/Images/country.png"/>
  13:              </DataTemplate>
  14:          </ig:XamDataTree.ExpandedIconTemplate>
  15:          <ig:XamDataTree.CollapsedIconTemplate>
  16:              <DataTemplate>
  17:                  <Image Source="/AccessSharePoint;component/Images/country2.png"/>
  18:              </DataTemplate>                    
  19:          </ig:XamDataTree.CollapsedIconTemplate>
  20:          <ig:XamDataTree.GlobalNodeLayouts>
  21:              <ig:NodeLayout Key="ItemsLayout" TargetTypeName="ListInfo" DisplayMemberPath="Title">
  22:  
  23:              </ig:NodeLayout>
  24:              <ig:NodeLayout Key="CreateDateLayout" TargetTypeName="ItemDetails"  DisplayMemberPath="Created">
  25:                  <ig:NodeLayout.ItemTemplate>
  26:                      <DataTemplate>
  27:                          <StackPanel Orientation="Horizontal">
  28:                              <Image Source="/AccessSharePoint;component/Images/News.png"/>
  29:                              <TextBlock Text="Created:"/>
  30:                              <TextBlock Text="{Binding Data.Created}"/>
  31:                          </StackPanel>
  32:                      </DataTemplate>
  33:                  </ig:NodeLayout.ItemTemplate>
  34:              </ig:NodeLayout>
  35:          </ig:XamDataTree.GlobalNodeLayouts>
  36:      </ig:XamDataTree>
  37:      <ig:XamGrid Grid.Column="1" x:Name="xamSpListItemsGrid" Margin="10"></ig:XamGrid>
  38:  </Grid>

 

Add a button and attach an event handler, that receives all list in the specified SharePoint site.

   1: <Button Content="Load Data from SharePoint"  Height="23" 
   2: HorizontalAlignment="Left" Name="btnLoadData" VerticalAlignment="center" 
   3: Width="165" Click="BtnLoadDataClick" />

 

Display SharePoint lists

C# code: add several variables used to maintain the SharePoint data.

   1: private ClientContext _clientContext = null;
   2: private ListCollection _collList;
   3: private List _oList = null;
   4: private ListItemCollection _oListItems = null;
   5: private Web _oWebSite = null;
   6: private const string Url = http://[SharePointSiteUrl];

 

Create a hierarchy of  viewmodels that will use to place SharePoint data.

   1: #region public class BaseViewModel
   2: /// <summary>
   3: /// Base view model. Contains implementation of the INotifyPropertyChanged interface
   4: /// </summary>
   5: public class BaseViewModel : INotifyPropertyChanged
   6: {
   7:  
   8:     #region INotifyPropertyChanged Members
   9:  
  10:     public event PropertyChangedEventHandler PropertyChanged;
  11:  
  12:     #endregion
  13:  
  14:     protected void OnPropertyChanged(string propertyName)
  15:     {
  16:         PropertyChangedEventHandler handler = PropertyChanged;
  17:         if (handler != null)
  18:             handler(this, new PropertyChangedEventArgs(propertyName));
  19:  
  20:     }
  21: }
  22: #endregion //public class BaseViewModel
  23:  
  24: #region public class ListInfo
  25: public class ListInfo : BaseViewModel
  26: {
  27:     //public string Title { get; set; }
  28:  
  29:     #region Title
  30:  
  31:     private string _title;
  32:  
  33:     public string Title
  34:     {
  35:         get { return _title; }
  36:         set
  37:         {
  38:             if (_title != value)
  39:             {
  40:                 _title = value;
  41:                 OnPropertyChanged("Title");
  42:             }
  43:         }
  44:     }
  45:     #endregion //Title
  46:  
  47:     #region Description
  48:  
  49:     private string _description;
  50:  
  51:     public string Description
  52:     {
  53:         get { return _description; }
  54:         set
  55:         {
  56:             if (_description != value)
  57:             {
  58:                 _description = value;
  59:                 OnPropertyChanged("Description");
  60:             }
  61:         }
  62:     }
  63:     #endregion //Description
  64:  
  65:  
  66:     #region ItemDetails
  67:  
  68:     private IEnumerable<ItemDetails> _itemDetails;
  69:  
  70:     public IEnumerable<ItemDetails> ItemDetails
  71:     {
  72:         get { return _itemDetails; }
  73:         set
  74:         {
  75:             if (_itemDetails != value)
  76:             {
  77:                 _itemDetails = value;
  78:                 OnPropertyChanged("ItemDetails");
  79:             }
  80:         }
  81:     }
  82:     #endregion //ItemDetails
  83: } 
  84: #endregion //public class ListInfo
  85:  
  86: #region public class ItemDetails
  87:  
  88: public class ItemDetails : BaseViewModel
  89: {
  90:     #region Created
  91:  
  92:     private string _created;
  93:  
  94:     public string Created
  95:     {
  96:         get { return _created; }
  97:         set
  98:         {
  99:             if (_created != value)
 100:             {
 101:                 _created = value;
 102:                 OnPropertyChanged("Created");
 103:             }
 104:         }
 105:     }
 106:     #endregion //Created
 107: }
 108:  #endregion public class ItemDetails

 

Implement an event handler that creates a ClienContext instance and gets all list from the specified SharePoint page.

   1: #region BtnLoadDataClick
   2:  private void BtnLoadDataClick(object sender, RoutedEventArgs e)
   3:  {
   4:      using (var clientContext = new ClientContext(Url))
   5:      {
   6:          _oWebSite = clientContext.Web;
   7:          _collList = _oWebSite.Lists;
   8:          clientContext.Load(_collList);
   9:          clientContext.ExecuteQueryAsync(OnQuerySucceeded, OnQueryFailed);
  10:      }
  11:  }
  12:  #endregion //BtnLoadDataClick

 

   1: #region OnQuerySucceeded
   2: private void OnQuerySucceeded(object sender, ClientRequestSucceededEventArgs args)
   3: {
   4:     //DisplayLists method converts the List items to Class Properties
   5:     //and binds them to the Silverlight User Interface.
   6:     Dispatcher.BeginInvoke(new Action(DisplayLists));
   7: }
   8: #endregion //OnQuerySucceeded

 

Note: Silverlight query model is asynchronous and must pass delegates for callback methods as parameters in the ExecuteQueryAsync(OnQuerySucceeded, OnQueryFailed)  method.
Also to update the Silverlight UI use delegate using the Dispatacher object of the thread that created the UI by calling BeginInvoke() method.

Create a collection that implements IQuerable<ItemDetails>  interface and set it to the XamDataTree ItemsSource property:

   1: #region DisplayLists
   2: private void DisplayLists()
   3: {
   4:  
   5:     var list = _collList.ToList().Select(s => new ListInfo 
   6:     { Title = s.Title, Description = s.Description, 
   7:         ItemDetails = new ObservableCollection<ItemDetails> { new ItemDetails { Created = s.Created.ToShortDateString() } } 
   8:     });
   9:  
  10:     xamSpListTree.ItemsSource = list;
  11: }
  12: #endregion

 

Run the application

SPAccessSl_Pic05[1]

Click the “Load Data from SharePoint” button to receive all SharePoint lists in the requested page.

Now you have in the Infragistics Silverlight DataTree all lists from the specified URL.

SPAccessSl_Pic06[1]

Display SharePoint list items

The next step is to display items from a specified SharePoint list.

Add an event handler that gets all items form a SharePoint list and attach it to the DataTree event, named  ActiveNodeChanged.

   1: #region XamSpListTreeActiveNodeChanged
   2: private void XamSpListTreeActiveNodeChanged(object sender, Infragistics.Controls.Menus.ActiveNodeChangedEventArgs e)
   3: {
   4:     var info = e.NewActiveTreeNode.Data as ListInfo;
   5:     if (info != null)
   6:     {
   7:         var list = ((ListInfo)e.NewActiveTreeNode.Data);
   8:         ShowListItemTitles(list.Title);
   9:  
  10:     }
  11: }
  12: #endregion //XamSpListTreeActiveNodeChanged

 

   1: #region ShowListItemTitles
   2: private void ShowListItemTitles(string listName)
   3: {
   4:     _clientContext = ClientContext.Current;
   5:     if (_clientContext == null)
   6:     {
   7:         _clientContext = new ClientContext(Url);
   8:     }
   9:     using (_clientContext)
  10:     {
  11:         _oWebSite = _clientContext.Web;
  12:         _oList = _oWebSite.Lists.GetByTitle(listName);
  13:         _oListItems = _oList.GetItems(CamlQuery.CreateAllItemsQuery());
  14:         _clientContext.Load(_oListItems);
  15:         _clientContext.ExecuteQueryAsync(OnListItemsQuerySucceeded, OnQueryFailed);
  16:     }
  17: }
  18: #endregion //ShowListItemTitles

 

   1: #region OnListItemsQuerySucceeded
   2:   private void OnListItemsQuerySucceeded(object sender, ClientRequestSucceededEventArgs args)
   3:   {
   4:       //DisplayListsItems method converts the List items to Class Properties
   5:       //and binds them to the Silverlight User Interface.
   6:       Dispatcher.BeginInvoke(new Action(DisplayListsItems));
   7:   }
   8:   #endregion //OnListItemsQuerySucceeded

 

Create a collection that implements IQuerable<ListInfo> interface and set it to the XamGrid ItemsSource property:

 

   1: #region DisplayListsItems
   2: private void DisplayListsItems()
   3: {
   4:     try
   5:     {
   6:         var list = _oListItems.ToList().Select(s => new ListInfo
   7:                                                         {
   8:                                                             Title = s["Title"].ToString(), Description = ""
   9:                                                         });
  10:         xamSpListItemsGrid.ItemsSource = list;
  11:     }
  12:     catch (Exception ex)
  13:     {
  14:         MessageBox.Show("Error:" + ex.Message);
  15:     }
  16:  
  17: }
  18: #endregion //DisplayListsItems

 

Run the sample application again. When you select the tree node all list items are displayed in the Infragistics Silverlight Grid

SPAccessSl_Pic07[1]

SPAccessSl_Pic08[1]

Conclusion

In this article, we have seen how to use ‘Silverlight Client Object Model’ to fetch the SharePoint Lists and List data when the Silverlight application runs outside the SharePoint context. In this blog are mentioned required settings to be possible to maintain SharePoint data.

Source code you could download here.