SharePoint Blog

Customizing SharePoint’s Mobile Experience

As so oft, you can always choose to do your own thing. A good example of feeling the urge of choosing your own way instead of extending a SharePoint out-of-the-box feature is when you come to a point, where your customer asks you to port his intranet WCSM portal to a mobile solution. Having not come to this bridge before, I of course started my journey googling to see how I can achieve this. Most notably, SharePoint 2010 as well as MOSS are already prepared for showing content on mobile devices. You can give it try, when you append ?mobile=1 to your SharePoint site URL e.g. “http://MyServer/MySite/default.aspx?Mobile=1″. If the legacy MobileRedirection feature has been activated for the Web site using the following PowerShell command Enable-SPFeature –identity “MobileRedirection” –URL http://MyServer/MySite, then navigating to “http://MyServer/MySite/m” on either a computer or mobile device browser also causes SharePoint to divert you to its mobile homepage.

Everybody who has ever tried to navigate to the mobile homepage should be familiar with the resulting page. For a SharePoint 2010 Foundation Teamsite it looks as follows.

OOTB Mobile Team Site

I don’t want to start a discussion whether you like this interface or not or whether it fits your needs. Much more important for this post is the fact that if you navigate to a SharePoint publishing portal’s mobile homepage, you’ll find that the Pages Library is not listed. After the initial disappointment and having thought about it for a couple of more minutes it all makes sense. You probably heavily customized your Publishing Page ContentTypes and their corresponding Publishing Page Templates. SharePoint has no clue how to aggregate all that information into a comprehensible list. It simply is not aware of the columns you created to save the page’s content in. Still, if you’re curious what it may look like, you should have a look at Jamie McAllister’s post here http://the-north.com/sharepoint/post/Exposing-your-MOSS-WCM-to-Mobile-Devices.aspx on how to you can accomplish almost anything using a crowbar and make the Pages Library appear afterall! However, in the end he recommends to go for variations. Whilst that may be (partially) true, I still believe I need another solution for the mobile WCMS homepage. Personally, I’m a big fan of the WPTouch interface for WordPress. It’s a clean and neat way to publish a content list using teasers. Even when it’s optimized for blogs, I believe it can be reused for listing your company’s latest news and announcements.

Unfortunately, I don’t have SharePoint Server installed on my laptop. But for the point I want to make I don’t need it anyway. Whether I’ll grab some data from a Shared Documents Library or from a Pages Library in the end is not a huge difference. In the end, I want to reuse as much SharePoint Mobile Experience logic as possible. I don’t want to run off and develop something from scratch that is incompatible with SharePoint or ASP.NET’s mobile solution. However, I want to be able to replace the content between header and footer shown above. All I want to show is an aggregated list with the document names in all Document Libraries in my SiteCollection. As it turns out, that’s rather easy.

I started of by creating a new Empty SharePoint Project. Since the solution needs to copy files to the server’s file system, it cannot be created as a sandboxed solution.

The first thing I now need is a customized mobile homepage and tell SharePoint that it should use my newly created mobile homepage instead of the standard one. This means that I somehow have to customize how SharePoint redirects. This can be achieved by creating a new SharePoint RenderingTemplate that resides in the root of the {SharePointRoot}\Template\CONTROLTEMPLATES\ directory as follows.

<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Assembly Name="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 

<%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
<%@ Register TagPrefix="SPMobile" Namespace="Microsoft.SharePoint.MobileControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 

<%@ Control Language="C#" %>

<SharePoint:RenderingTemplate runat="Server" id="Mobile_STS_HomePage_Redirect">
    <Template>
		<SPMobile:SPMobileHomePageRedirection id="HomePageRedirect_MobileExperience" RunAt="Server" PageFileName="MobileExperience/home.aspx" />
	</Template>
</SharePoint:RenderingTemplate>

The first thing to notice is the id of the RenderingTemplate is Mobile_STS_HomePage_Redirect. Upon redirecting a user, SharePoint looks for a RenderingTemplate using the following algorithm: Mobile_ID-of-the-current-site-defintion_HomePage_Redirect. Since I’m experimenting with a SharePoint Foundation Teamsite, I need to use STS (for the out-of-the-box SiteDefinitions, SharePoint also accepts the name of the SiteDefinition but I also could have gone for Mobile_1_HomePage_Redirect instead). The second interesting thing is the PageFileName of the SPMobile:SPMobileHomePageRedirection control. This should point to the customized mobile homepage. SharePoint expects it to be somewhere in the {SharePointRoot}\Template\LAYOUTS\MOBILE directory. In my case I’ve created my own sub directory below it to make sure I’m not overwriting anything that came out of the box.

The second step is to create my own customized homepage. In Visual Studio I’ve mapped the SharePoint MOBILE folder, created a sub directory called MobileExperience and added a new text file to it that I then renamed in home.aspx. A mobile homepage is something quite different from other SharePoint Application and WebPart Pages. It doesn’t contain a body as such. It merely hosts an SPMobileForm. I’ve copied the code for mine below.

<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>

<%@ Register TagPrefix="mobile" Namespace="System.Web.UI.MobileControls" Assembly="System.Web.Mobile, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" %>
<%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="SPMobile" Namespace="Microsoft.SharePoint.MobileControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@ Page Language="C#" EnableViewState="true" inherits="Mvw.SharePoint.MobileExperience.Helpers.MobileExperienceHomePage, $SharePoint.Project.AssemblyFullName$"%>

<mobile:StyleSheet RunAt="Server" ID="SharePointMobileStyleSheet" />

<script runat="server">
protected override Microsoft.SharePoint.SPBasePermissions RightsRequired
{
	get
	{
		return base.RightsRequired | Microsoft.SharePoint.SPBasePermissions.ViewPages;
	}
}
</script>

<SPMobile:SPMobileForm RunAt="Server" PageType="HomePage" Paginate="true">
	<DeviceSpecific>
		<Choice Filter="supportsCss">
			<HeaderTemplate>
				<SPMobile:SPMobileComponent RunAt="Server" Templatename="MobilePageTitleWithCss"      Weightless="true" />
			</HeaderTemplate>
			<FooterTemplate>
				<SPMobile:SPMobileComponent RunAt="Server" Templatename="MobilePageNavigationWithCss" Weightless="true" />
			</FooterTemplate>
		</Choice>
		<Choice>
			<HeaderTemplate>
				<SPMobile:SPMobileControlContainer RunAt="Server" Weightless="true">
					<SPMobile:SPMobilePageTitle RunAt="Server" />
					<SPMobile:SPMobileComponent RunAt="Server" TemplateName="MobileDefaultSeparator" />
				</SPMobile:SPMobileControlContainer>
			</HeaderTemplate>
			<FooterTemplate>
				<SPMobile:SPMobileControlContainer RunAt="Server" Weightless="true">
					<SPMobile:SPMobileComponent      RunAt="Server" Templatename="MobilePaginateNavigation" />
					<SPMobile:SPMobileComponent      RunAt="Server" TemplateName="MobileDefaultSeparator" />
					<SPMobile:SPMobilePageNavigation RunAt="Server" />
				</SPMobile:SPMobileControlContainer>
			</FooterTemplate>
		</Choice>
	</DeviceSpecific>
    <ContentTemplate>
        <SPMobile:SPMobileComponent RunAt="Server" Templatename="MobileExperienceContentTemplate" />
    </ContentTemplate>
</SPMobile:SPMobileForm>

Basically, I’ve copied SharePoint’s mobile homepage for WebPart pages which you can find here {SharePointRoot}\Template\LAYOUTS\MOBILE\mblwp.aspx. I would be running out of virtual paper if I would be discussing the code above line by line. However, a couple of things I should mention. Apparently, you can create device specific templates. I haven’t dived into this but understood it would work in conjunction with the compat.browsers file that you’ll find in your WebApplication’s App_Browsers directory on the file system. A second thing to notice is that I’ve added a ContentTemplate at the end but left the HeaderTemplate and FooterTemplate intact. Remember, I only want to display my own kind of list that shows all document names available in the current SiteCollection. The ContentTemplate refers to a RenderingTemplate that I now need to create. As this is also a RenderingTemplate I can in fact easily add it to file I created in the CONTROLTEMPLATES directory for the mobile redirection template as follows

<SharePoint:RenderingTemplate runat="Server" id="MobileExperienceContentTemplate">
    <Template>
        <asp:gridview id="gvMyGridView" runat="Server" />
        <SPMobile:SPMobileLabel id="lblMyGridViewRows" RunAt="Server" />
    </Template>
</SharePoint:RenderingTemplate>

The fourth and last thing I need to do to make this work is addding some logic to my mobile homepage. If you scroll back to the code above, you’ll notice that the page inherits from Mvw.SharePoint.MobileExperience.Helpers.MobileExperienceHomePage. This is in fact the codebehind class if you want to call it that way.

using System;
using System.Data;
using System.Web.UI;
using System.Web.UI.WebControls;

using Microsoft.SharePoint;
using Microsoft.SharePoint.MobileControls;

namespace Mvw.SharePoint.MobileExperience.Helpers
{
    public class MobileExperienceHomePage : SPMobilePage
    {
        internal GridView gvMyGridview;
        internal SPMobileLabel lblMyGridViewRows;

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            gvMyGridview = (GridView)this.FindControl("gvMyGridview");
            lblMyGridViewRows = (SPMobileLabel)this.FindControl("lblMyGridViewRows");

            using (SPWeb web = SPContext.Current.Web)
            {
                SPSiteDataQuery query = new SPSiteDataQuery();

                query.Lists = "<Lists ServerTemplate=\"101\" />";

                query.ViewFields = "<FieldRef Name=\"LinkFilename\" />" + 
                    "<FieldRef Name=\"Modified\" />";

                query.Query = "<OrderBy>" +
                                "<FieldRef Name=\"Modified\" />" +
                              "</OrderBy>";

                query.Webs = "<Webs Scope=\"SiteCollection\" />";

                DataTable dt = web.GetSiteData(query);
                DataView dv = new DataView(dt);

                // Set up the field bindings.
                BoundField fldName = new BoundField();
                fldName.HeaderText = "Name";
                fldName.DataField = "LinkFilename";
                gvMyGridview.Columns.Add(fldName);

                BoundField fldModified = new BoundField();
                fldModified.HeaderText = "Modified";
                fldModified.DataField = "Modified";
                gvMyGridview.Columns.Add(fldModified);

                gvMyGridview.AutoGenerateColumns = false;
                gvMyGridview.DataSource = dv;
                gvMyGridview.DataBind();

                // gvMyGridview.AllowSorting = true;
                gvMyGridview.HeaderStyle.Font.Bold = true;

                lblMyGridViewRows.Text = "No. of documents found: " + dv.Count;
            }
        }
    }
}

The most obvious thing you notice when you glance through the code above should be that the mobile homepage extends SPMobilePage.

At this point my Visual Studio project looks as follows (make sure not to overlook the reference to System.Web.Mobile).

Visual Studio Project

If you F5 the project and take it for a test drive you might run into the same problems as I did. Somehow the redirection didn’t work immediately and instead of my customized homepage the out-of-the-box homepage was loaded. After ploughing through the log files I noticed that SharePoint couldn’t find the redirection control. So instead of F5′ing the project I deployed the project and pointed my browser to my SiteCollection and things started to work.

Customized Mobile Team Site

I’m fully aware that I’ve kept everything extremely simple in this example. I’m also not going to make things look better with CSS or whatsoever. I just want to show you, how easy it is to customize SharePoint Mobile Experience. Moreover, it should give you a headstart when you want to develop a WPTouch clone for SharePoint!

Copyright ©2012. All Rights Reserved.