Getting list items from SharePoint Online to Windows phone

Getting data from SharePoint Online to Windows phone is not too complicated. But I am referencing here only projects targeting Windows 8.0, as Microsoft supply a SharePoint SDK only for this platform and I am not aware yet of a SDK targeting Windows 8.1.

As a concrete example, I have created an announcement list called “Company News” in a SharePoint Online environmental and I trying to display it in a client mobile application. The structure of announcement list is simple, being only interested in getting only 3 columns: Title (single line of text), Body (plain text), and Category (choice field).

I will start presenting structure of my project, which is a Silverlight blank application for Windows phone, and explain it step by step.

Sprint Structure

CompanyUpdate.cs is a simple class representing data structure of my SharePoint list. A list of CompanyUpdate objects will be used as source for a longlistselector control.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace SPRInt
{
    class CompanyUpdate
    {
        public string Title { get; set; }
        public string Category { get; set; }
        public string Body { get; set; }

    }
}

ExtensionMethods.cs contains a single static class with a single extension method, designed to replace br tags with /n and strip all other HTML tags. That’s because content of Body column contains HTML tags but my application is not HTML based.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace SPRInt
{
     public static class ExtendedMethods
    {
         public static string StripTags (this string input)
         {
             string _input = Regex.Replace(input, @"(<br */>)|(\[br */\])", "\n");
             _input = Regex.Replace(_input, @"(<.*?>)", String.Empty;
             return _input;
         }

    }
}

We are moving now to ListOperations.cs , which is actually the core of the application.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Phone;

namespace SPRInt
{
    class ListOperations
    {
        string url;

        /// <summary>
        /// List operations constructor
        /// </summary>
        /// <param name="url"></param>
        public ListOperations(string url)
        {
            this.url = url;
        }

        /// <summary>
        /// Get list items
        /// </summary>
        /// <param name="listName"></param>
        public void GetItems(string listName, Action<List<CompanyUpdate>> callback)
        {
            Authenticator sprintAuthenticator = new Authenticator();
            sprintAuthenticator.AuthenticationMode = ClientAuthenticationMode.MicrosoftOnline;
            sprintAuthenticator.CookieCachingEnabled = true;

            ClientContext ctx = new ClientContext(this.url);
            ctx.Credentials = sprintAuthenticator;

                List spList = ctx.Web.Lists.GetByTitle(listName);
                CamlQuery query = CamlQuery.CreateAllItemsQuery();
                ListItemCollection items = spList.GetItems(query);
                ctx.Load(items);

                ctx.ExecuteQueryAsync(
                    (Object sender, ClientRequestSucceededEventArgs args) => {
                        List<CompanyUpdate> companyUpdates = new List<CompanyUpdate>();
                        foreach (ListItem item in items)
                        {
                            CompanyUpdate cUpdate = new CompanyUpdate();
                            cUpdate.Title = Convert.ToString(item["Title"]);
                            cUpdate.Category = Convert.ToString(item["Category"]);
                            cUpdate.Body = Convert.ToString(item["Body"]).StripTags();
                            companyUpdates.Add(cUpdate);
                        }
                        callback(companyUpdates);
                    },
                    (Object sender, ClientRequestFailedEventArgs args) => {

                    }
                );

        }

    }
}

You can note I am using Microsoft.SharePoint.Client and Microsoft.SharePoint.Client.Phone namespaces in the file, these being available because I have SharePoint SDK for Windows phone libraries to my project. Being now able to use classes coming from these namespace, I can make use of Authenticator class (responsible to authenticate me with SharePoint Online) and other client object model classes. Class is instantiated with url of our SharePoint and has a method called GetItems which accepts two parameters: the name of the list and an action which serves as callback method.

It remains MainPage.xaml and associated cs file. There is nothing complicated with this file. It is a simple Silverlight page containing a LongListSelector. When page is loaded, data is getting from the SharePoint list and displayed into the LongListSelector.

<phone:PhoneApplicationPage
 x:Class="SPRInt.MainPage"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
 xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 mc:Ignorable="d"
 FontFamily="{StaticResource PhoneFontFamilyNormal}"
 FontSize="{StaticResource PhoneFontSizeNormal}"
 Foreground="{StaticResource PhoneForegroundBrush}"
 SupportedOrientations="Portrait" Orientation="Portrait"
 shell:SystemTray.IsVisible="True" Loaded="PhoneApplicationPage_Loaded">

 <!--LayoutRoot is the root grid where all page content is placed-->
 <Grid x:Name="LayoutRoot" Background="Transparent">
 <Grid.RowDefinitions>
 <RowDefinition Height="Auto"/>
 <RowDefinition Height="*" />
 </Grid.RowDefinitions>



 <!--TitlePanel contains the name of the application and page title-->
 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,12,28">
 <TextBlock Text="SPRInt for mobile" Style="{StaticResource PhoneTextNormalStyle}" />
 <TextBlock Text="News" Style="{StaticResource PhoneTextTitle1Style}"/>
 
 </StackPanel>

 <!-- Data displayed here -->
 <phone:LongListSelector Grid.Row="1" Name="lstCompanyNews" Margin="12,0,12,0">
 <phone:LongListSelector.ItemTemplate>
 <DataTemplate>
 <StackPanel Orientation="Vertical">
 <TextBlock Text="{Binding Title}" Style="{StaticResource companyupdatetitle}" />
 <TextBlock Text="{Binding Category}" Foreground="AliceBlue" />
 <TextBlock Text="{Binding Body}" Foreground="AliceBlue" />
 </StackPanel> 
 </DataTemplate>
 </phone:LongListSelector.ItemTemplate>

 </phone:LongListSelector>


 </Grid>

</phone:PhoneApplicationPage>
       
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Phone;
using Microsoft.Phone.Shell;

using SPRInt.Resources;

namespace SPRInt
{
 public partial class MainPage : PhoneApplicationPage
 {
 // Constructor
 public MainPage()
 {
 InitializeComponent();
 }

 private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
 {
 ListOperations ops = new ListOperations("https://sprint");
 Action<List<CompanyUpdate>> callback = (List<CompanyUpdate> items) =>
 {
 this.Dispatcher.BeginInvoke(() =>
 {

 this.lstCompanyNews.ItemsSource = items;
 });
 };
 ops.GetItems("Company News", callback);

 }

 }
}
Advertisements

Server rendering in SharePoint (applied to XsltListViewWebPart)

Microsoft is pushing SharePoint development as much as possible on client side by introducing JSLink. But still, I cannot consider old XSLT is dead. So in SharePoint 2013, server rendering is still an available option.

Server Render

To enable server render you just need to tick the Server Render checkbox and provide the path to an XSLT file in XSL link property. Once is enabled, customization will be done on external XSLT file.
There are some articles about how to customize the webpart, but most part of them are a little bit complicated. So I will resume my article on simple customization tasks very likely to be requested in real development.

Change content of a cell

Let’s assume we have field (single line of text), called location, and customer is requiring to display “My location + @Location” instead of location only. This is done pretty straight forward, as you can also note by looking on the code below.

<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" version="1.0" exclude-result-prefixes="xsl msxsl ddwrt" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:SharePoint="Microsoft.SharePoint.WebControls" xmlns:ddwrt2="urn:frontpage:internal" xmlns:o="urn:schemas-microsoft-com:office:office">
<xsl:include href="/_layouts/xsl/main.xsl"/> 
<xsl:include href="/_layouts/xsl/internal.xsl"/> 


<xsl:template name="ShowLocation" ddwrt:dvt_mode="body" match ="FieldRef[@Name='Location']" mode="Text_body" ddwrt:ghost="show">
<xsl:param name="thisNode" select="." />
<xsl:param name="location" select="$thisNode/@Location" />
<xsl:if test="$location != ''">
	<xsl:value-of select="concat('My location is ',$location)" disable-output-escaping="yes" />
</xsl:if>
</xsl:template>
</xsl:stylesheet>

The XSLT is overriding the default content of table cell. Please note it cannot affect TD itself tag or what is outside the TD tag. To change the TD itself, please see the next point.

Change the cell in the view

Sometimes, customer might request to change completely the table cell and its content. A possible reason is to apply a different CSS class on TD tag. Here is how you can do this.

<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" version="1.0" exclude-result-prefixes="xsl msxsl ddwrt" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:SharePoint="Microsoft.SharePoint.WebControls" xmlns:ddwrt2="urn:frontpage:internal" xmlns:o="urn:schemas-microsoft-com:office:office">
<xsl:include href="/_layouts/xsl/main.xsl"/> 
<xsl:include href="/_layouts/xsl/internal.xsl"/> 
<xsl:template name="ShowLocationWithTd" match="FieldRef[@Name='Location']" mode="printTableCellEcbAllowed" ddwrt:dvt_mode="body" ddwrt:ghost="show" xmlns:ddwrt2="urn:frontpage:internal">
<xsl:param name="thisNode" select="." />
<xsl:param name="location" select="$thisNode/@Location" />
<!-- I can change here even the parent tag, if required -->
<td class="mycustomcssclass">
	<xsl:value-of select="$location" disable-output-escaping="yes" />
</td>
</xsl:template>
</xsl:stylesheet>

Change the table row

Let’s go now to a level up, which mean table row. For example, customer required to change the table row into a different tag and display a custom content in it.

<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" version="1.0" exclude-result-prefixes="xsl msxsl ddwrt" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:SharePoint="Microsoft.SharePoint.WebControls" xmlns:ddwrt2="urn:frontpage:internal" xmlns:o="urn:schemas-microsoft-com:office:office">
<xsl:include href="/_layouts/xsl/main.xsl"/> 
<xsl:include href="/_layouts/xsl/internal.xsl"/> 

<xsl:template mode="Item" match="Row" ddwrt:ghost="show">
<xsl:param name="thisNode" select="." />
<xsl:param name="location" select="$thisNode/@Location" />
<!-- TD was changed with DIV -->
<div>
	<xsl:value-of select="$location" disable-output-escaping="yes" />
</div>
</xsl:template>
</xsl:stylesheet>

Change entire view

This is actually my favourite technique because I can easily change the view to look 100% different than default one (quick example in the picture below) and I can write my own and clear XSLT code.

XSLTFull Customization

The code to achieve this is simple and I dare to say is much clear than auto-generated one. The development becomes a simple xsl:for-each iteration, which can be done even by non-experienced developers.

<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" version="1.0" exclude-result-prefixes="xsl msxsl ddwrt" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:SharePoint="Microsoft.SharePoint.WebControls" xmlns:pcm="urn:PageContentManager" xmlns:ddwrt2="urn:frontpage:internal" xmlns:o="urn:schemas-microsoft-com:office:office" ddwrt:ghost="show_all"> 
<xsl:include href="/_layouts/xsl/main.xsl"/> 
<xsl:include href="/_layouts/xsl/internal.xsl"/> 
<xsl:variable name="Fields" select="$XmlDefinition/ViewFields/FieldRef[not(@Explicit='TRUE')]"/>

<xsl:template match="/" ddwrt:ghost="hide">
<div style="display:block; width:100%;">

	<!-- Show the toolbar-->
	<xsl:call-template name="ListViewToolbar"/>
	
	<!-- Displaying the records -->
	<xsl:for-each select="/dsQueryResponse/Rows/Row">
	<xsl:variable name="thisNode" select="." />
	<div style="width:100%; display:block;">
		<xsl:for-each select="$Fields"> 
			<xsl:variable name="FieldName" select="current()/@Name" /> 
			<xsl:variable name="FieldDisplayName" select="current()/@DisplayName" />       
			<div style="display:block; width:100%">
				<strong><xsl:value-of select="$FieldDisplayName" disable-output-escaping="yes" /></strong>: <xsl:value-of select="$thisNode/@*[name() = $FieldName]" disable-output-escaping="yes" />
			</div>
		</xsl:for-each>
	</div>
	<b /><br />
	</xsl:for-each>


</div>
</xsl:template>

</xsl:stylesheet>

I have presented here some concrete and simple examples about how to use XSLT for view customization. I will periodically update this article with new example and additional information, but if you have question, please don’t hesitate to contact me.

ddwrt namespace – extension functions detailed

Webparts like DataFormWebPart are still useful and powerful webparts, even if Microsoft is trying to push the SharePoint development to client side by introducing JSLink. One of the reason is because XSLT is extended to some functions coming from ddwrt namespace. These can be found and documented on this link. I am also extended the page by presenting how actually these functions can be used in your XSLT code.

Function Usage Output
GetFileExtension <xsl:value-of select=”ddwrt:GetFileExtension(‘excelfile.doc’)” /> doc
GetVar and SetVar <xsl:variable name=”MyVar” />
<xsl:value-of select=”ddwrt:SetVar(‘MyVar’,’My Value’)” />
<xsl:value-of select=”ddwrt:GetVar(‘MyVar’)” />
My Value
IsPrivilegedUser <xsl:if test=”ddwrt:IsPrivilegedUser() = false”>Not admin</xsl:if> Not admin
Limit <xsl:value-of select=”ddwrt:Limit(‘Long text’, 4,’…’)” /> Long…
Counter <xsl:value-of select=”ddwrt:Counter()” />,<xsl:value-of select=”ddwrt:Counter()” />,<xsl:value-of select=”ddwrt:Counter()” /> 1,2,3
FormatDate <xsl:value-of select=”ddwrt:FormatDate(‘2014-08-20T08:00:00Z’,1033,1)” /><br />
<xsl:value-of select=”ddwrt:FormatDate(‘2014-08-20T08:00:00Z’,1033,3)” /><br />
<xsl:value-of select=”ddwrt:FormatDate(‘2014-08-20T08:00:00Z’,1033,4)” /><br />
<xsl:value-of select=”ddwrt:FormatDate(‘2014-08-20T08:00:00Z’,1033,5)” /><br />
<xsl:value-of select=”ddwrt:FormatDate(‘2014-08-20T08:00:00Z’,1033,7)” /><br />
<xsl:value-of select=”ddwrt:FormatDate(‘2014-08-20T08:00:00Z’,1033,12)” /><br />
<xsl:value-of select=”ddwrt:FormatDate(‘2014-08-20T08:00:00Z’,1033,13)” /><br />
<xsl:value-of select=”ddwrt:FormatDate(‘2014-08-20T08:00:00Z’,1033,15)” />
8/20/2014
Wednesday, August 20, 2014
1:00 AM
8/20/2014 1:00 AM
Wednesday, August 20, 2014 1:00 AM
1:00:00 AM
8/20/2014 1:00:00 AM
Wednesday, August 20, 2014 1:00:00 AM
IfNew <xsl:if test=”ddwrt:IfNew(‘2014-08-20T08:00:00Z’) = ‘true'”>Recent</xsl:if>
ListProperty  <xsl:value-of select=”ddwrt:ListProperty(‘itemCount’)” />
<xsl:value-of select=”ddwrt:ListProperty(‘title’)” />
UserLookup <xsl:value-of select=”ddwrt:UserLookup($UserID,’ID’)” />
<xsl:value-of select=”ddwrt:UserLookup($UserID,’Email’)” />
<xsl:value-of select=”ddwrt:UserLookup($UserID,’Login’)” />

I consider these functions very valuable. I personally used with some success GetVar and SetVar for making more complicated calculation in the webpart without being forced to call XSLT templates recursively. So, if you still develop in XSLT, which is not a bad idea, you can look if you can use these functions. . If you can see this attribute, xmlns:ddwrt=http://schemas.microsoft.com/WebParts/v2/DataView/runtime, this means you can use them.