Thursday, 2 June 2011

SharePoint Application Page With Ribbon Only Master Page

Overview
I recently created a site which contained a Silverlight (surprise surprise!) web part of fixed size as designed, however the users requested that it should be maximised with the SharePoint menus and headings removed to increase the footprint of the application. I didn't want to change the site definition master page, so decided to create a stripped down master page with only a ribbon and an application page with the SL app hard coded into the page to allow it to resize properly.

Master Page
I need to acknowledge Randy Drisgill for the base master pages. I stripped down the _starter_foundation.master page to look like the following (sorry about the lack of colour, it was making the browser rendering too slow):

<%@ Master language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="wssuc" TagName="Welcome" src="~/_controltemplates/Welcome.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="DesignModeConsole" src="~/_controltemplates/DesignModeConsole.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="MUISelector" src="~/_controltemplates/MUISelector.ascx" %>
<html xmlns="
http://www.w3.org/1999/xhtml" lang="<%$Resources:wss,language_value %>" dir="<%$Resources:wss,multipages_direction_dir_value %>" runat="server">
<head runat="server">

 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <meta http-equiv="Expires" content="0"/>
 <meta http-equiv="X-UA-Compatible" content="IE=8"/>

 <!-- robots -->
 <SharePoint:RobotsMetaTag runat="server"/>

 <!-- page title - overridden by asp:content on pages or page layouts -->
 <title runat="server"><asp:ContentPlaceHolder id="PlaceHolderPageTitle" runat="server">SiteName</asp:ContentPlaceHolder></title>

 <!-- favicon -->
 <SharePoint:SPShortcutIcon runat="server" IconUrl="/Style Library/sitename/favicon.ico"/>

 <!-- all OOTB css -->
 <SharePoint:CssLink runat="server" Version="4"/>
 <SharePoint:Theme runat="server"/>

 <!-- page manager interacts with script and the sharepoint object model -->
 <SharePoint:SPPageManager runat="server"/>

 <!-- unified logging service -->
 <SharePoint:ULSClientConfig runat="server"/>

 <!-- identifies to scripting elements that this is a v4 master page. required for scrolling? -->
 <script type="text/javascript">
  var _fV4UI = true;
 </script>

 <!-- load SharePoint javascript -->
 <SharePoint:ScriptLink language="javascript" Defer="true" runat="server"/>

  <style type="text/css">
  html, body {
     height: 100%;
     overflow: none;
        }

        body {
         padding: 0;
         margin: 0;
        }
 </style>

 <!-- link to our custom css  -->
 <SharePoint:CssRegistration name="/Style Library/sitename/style.css" After="corev4.css" runat="server"/>

 <!-- javascript to override the active-x message in ie
  // See
http://blog.drisgill.com/2010/02/removing-name-activex-control-warning.html for more info
  // Remove if the IM pressence icons are needed in SharePoint
 -->
 <script type="text/javascript">
  function ProcessImn(){}
  function ProcessImnMarkers(){}
 </script>

 <!-- additional header delegate control -->
 <SharePoint:DelegateControl runat="server" ControlId="AdditionalPageHead" AllowMultipleControls="true"/>

 <!-- additional header placeholder - overridden by asp:content on pages or page layouts -->
 <asp:ContentPlaceHolder id="PlaceHolderAdditionalPageHead" runat="server"/> 

 <!-- microsoft says these should always be inside the head tag. -->
    <asp:ContentPlaceHolder id="PlaceHolderBodyAreaClass" runat ="server"/>
 <asp:ContentPlaceHolder id="PlaceHolderTitleAreaClass" runat ="server"/>
</head>

<body onload="javascript:_spBodyOnLoadWrapper();">
<form runat="server" onsubmit="return _spFormOnSubmitWrapper();" style="height:100%">
<!-- handles SharePoint scripts -->
<asp:ScriptManager id="ScriptManager" runat="server" EnablePageMethods="false" EnablePartialRendering="true" EnableScriptGlobalization="false" EnableScriptLocalization="true" />

<!-- controls the web parts and zones -->
<WebPartPages:SPWebPartManager runat="server"/>

<!-- =====  Begin Ribbon ============================================================ -->
<div id="s4-ribbonrow" class="s4-pr s4-ribbonrowhidetitle">
 <div id="s4-ribboncont">

  <!-- ribbon starts here -->
  <SharePoint:SPRibbon
   runat="server"
   PlaceholderElementId="RibbonContainer"
   CssFile="">

   <!-- ribbon left side content starts here -->
   <SharePoint:SPRibbonPeripheralContent
    runat="server"
    Location="TabRowLeft"
    CssClass="ms-siteactionscontainer s4-notdlg">

     <!-- site actions -->
     <span class="ms-siteactionsmenu" id="siteactiontd">
     <SharePoint:SiteActions runat="server" accesskey="<%$Resources:wss,tb_SiteActions_AK%>" id="SiteActionsMenuMain"
      PrefixHtml=""
      SuffixHtml=""
      MenuNotVisibleHtml="&amp;nbsp;"
      >
      <CustomTemplate>
      <SharePoint:FeatureMenuTemplate runat="server"
       FeatureScope="Site"
       Location="Microsoft.SharePoint.StandardMenu"
       GroupId="SiteActions"
       UseShortId="true"
       >
       <SharePoint:MenuItemTemplate runat="server" id="MenuItem_EditPage"
        Text="<%$Resources:wss,siteactions_editpage%>"
        Description="<%$Resources:wss,siteactions_editpagedescriptionv4%>"
        ImageUrl="/_layouts/images/ActionsEditPage.png"
        MenuGroupId="100"
        Sequence="110"
        ClientOnClickNavigateUrl="javascript:ChangeLayoutMode(false);"
        />
       <SharePoint:MenuItemTemplate runat="server" id="MenuItem_TakeOffline"
        Text="<%$Resources:wss,siteactions_takeoffline%>"
        Description="<%$Resources:wss,siteactions_takeofflinedescription%>"
        ImageUrl="/_layouts/images/connecttospworkspace32.png"
        MenuGroupId="100"
        Sequence="120"
        />
       <SharePoint:MenuItemTemplate runat="server" id="MenuItem_CreatePage"
        Text="<%$Resources:wss,siteactions_createpage%>"
        Description="<%$Resources:wss,siteactions_createpagedesc%>"
        ImageUrl="/_layouts/images/NewContentPageHH.png"
        MenuGroupId="200"
        Sequence="210"
        UseShortId="true"
        ClientOnClickScriptContainingPrefixedUrl="if (LaunchCreateHandler('Page')) { OpenCreateWebPageDialog('~site/_layouts/createwebpage.aspx') }"
        PermissionsString="AddListItems, EditListItems"
        PermissionMode="All" />
       <SharePoint:MenuItemTemplate runat="server" id="MenuItem_CreateDocLib"
        Text="<%$Resources:wss,siteactions_createdoclib%>"
        Description="<%$Resources:wss,siteactions_createdoclibdesc%>"
        ImageUrl="/_layouts/images/NewDocLibHH.png"
        MenuGroupId="200"
        Sequence="220"
        UseShortId="true"
        ClientOnClickScriptContainingPrefixedUrl="if (LaunchCreateHandler('DocLib')) { GoToPage('~site/_layouts/new.aspx?FeatureId={00bfea71-e717-4e80-aa17-d0c71b360101}&amp;ListTemplate=101') }"
        PermissionsString="ManageLists"
        PermissionMode="Any"
        VisibilityFeatureId="00BFEA71-E717-4E80-AA17-D0C71B360101" />
       <SharePoint:MenuItemTemplate runat="server" id="MenuItem_CreateSite"
        Text="<%$Resources:wss,siteactions_createsite%>"
        Description="<%$Resources:wss,siteactions_createsitedesc%>"
        ImageUrl="/_layouts/images/newweb32.png"
        MenuGroupId="200"
        Sequence="230"
        UseShortId="true"
        ClientOnClickScriptContainingPrefixedUrl="if (LaunchCreateHandler('Site')) { STSNavigate('~site/_layouts/newsbweb.aspx') }"
        PermissionsString="ManageSubwebs,ViewFormPages"
        PermissionMode="All" />
       <SharePoint:MenuItemTemplate runat="server" id="MenuItem_Create"
        Text="<%$Resources:wss,siteactions_create%>"
        Description="<%$Resources:wss,siteactions_createdesc%>"
        MenuGroupId="200"
        Sequence="240"
        UseShortId="true"
        ClientOnClickScriptContainingPrefixedUrl="if (LaunchCreateHandler('All')) { STSNavigate('~site/_layouts/create.aspx') }"
        PermissionsString="ManageLists, ManageSubwebs"
        PermissionMode="Any" />
       <SharePoint:MenuItemTemplate runat="server" id="MenuItem_ViewAllSiteContents"
        Text="<%$Resources:wss,quiklnch_allcontent%>"
        Description="<%$Resources:wss,siteactions_allcontentdescription%>"
        ImageUrl="/_layouts/images/allcontent32.png"
        MenuGroupId="300"
        Sequence="302"
        UseShortId="true"
        ClientOnClickNavigateUrl="~site/_layouts/viewlsts.aspx"
        PermissionsString="ViewFormPages"
        PermissionMode="Any" />
        <SharePoint:MenuItemTemplate runat="server" id="MenuItem_EditSite"
        Text="<%$Resources:wss,siteactions_editsite%>"
        Description="<%$Resources:wss,siteactions_editsitedescription%>"
        ImageUrl="/_layouts/images/SharePointDesigner32.png"
        MenuGroupId="300"
        Sequence="304"
        UseShortId="true"
        ClientOnClickScriptContainingPrefixedUrl="EditInSPD('~site/',true);"
        PermissionsString="AddAndCustomizePages"
        PermissionMode="Any"
       /> 
       <SharePoint:MenuItemTemplate runat="server" id="MenuItem_SitePermissions"
        Text="<%$Resources:wss,people_sitepermissions%>"
        Description="<%$Resources:wss,siteactions_sitepermissiondescriptionv4%>"
        ImageUrl="/_layouts/images/Permissions32.png"
        MenuGroupId="300"
        Sequence="310"
        UseShortId="true"
        ClientOnClickNavigateUrl="~site/_layouts/user.aspx"
        PermissionsString="EnumeratePermissions"
        PermissionMode="Any" />
       <SharePoint:MenuItemTemplate runat="server" id="MenuItem_Settings"
        Text="<%$Resources:wss,settings_pagetitle%>"
        Description="<%$Resources:wss,siteactions_sitesettingsdescriptionv4%>"
        ImageUrl="/_layouts/images/settingsIcon.png"
        MenuGroupId="300"
        Sequence="320"
        UseShortId="true"
        ClientOnClickNavigateUrl="~site/_layouts/settings.aspx"
        PermissionsString="EnumeratePermissions,ManageWeb,ManageSubwebs,AddAndCustomizePages,ApplyThemeAndBorder,ManageAlerts,ManageLists,ViewUsageData"
        PermissionMode="Any" />
       <SharePoint:MenuItemTemplate runat="server" id="MenuItem_CommitNewUI"
        Text="<%$Resources:wss,siteactions_commitnewui%>"
        Description="<%$Resources:wss,siteactions_commitnewuidescription%>"
        ImageUrl="/_layouts/images/visualupgradehh.png"
        MenuGroupId="300"
        Sequence="330"
        UseShortId="true"
        ClientOnClickScriptContainingPrefixedUrl="GoToPage('~site/_layouts/prjsetng.aspx')"
        PermissionsString="ManageWeb"
        PermissionMode="Any"
        ShowOnlyIfUIVersionConfigurationEnabled="true" />
      </SharePoint:FeatureMenuTemplate>
      </CustomTemplate>
       </SharePoint:SiteActions></span>

     <!-- global navigation dhtml popout menu -->
     <asp:ContentPlaceHolder id="PlaceHolderGlobalNavigation" runat="server">
     <SharePoint:PopoutMenu
      runat="server"
      ID="GlobalBreadCrumbNavPopout"
      IconUrl="/_layouts/images/fgimg.png"
      IconAlt="<%$Resources:wss,master_breadcrumbIconAlt%>"
      IconOffsetX=0
      IconOffsetY=112
      IconWidth=16
      IconHeight=16
      AnchorCss="s4-breadcrumb-anchor"
      AnchorOpenCss="s4-breadcrumb-anchor-open"
      MenuCss="s4-breadcrumb-menu">
      <div class="s4-breadcrumb-top">
       <asp:Label runat="server" CssClass="s4-breadcrumb-header" Text="<%$Resources:wss,master_breadcrumbHeader%>" />
      </div>
      <asp:ContentPlaceHolder id="PlaceHolderTitleBreadcrumb" runat="server">
       <SharePoint:ListSiteMapPath
        runat="server"
        SiteMapProviders="SPSiteMapProvider,SPContentMapProvider"
        RenderCurrentNodeAsLink="false"
        PathSeparator=""
        CssClass="s4-breadcrumb"
        NodeStyle-CssClass="s4-breadcrumbNode"
        CurrentNodeStyle-CssClass="s4-breadcrumbCurrentNode"
        RootNodeStyle-CssClass="s4-breadcrumbRootNode"
        NodeImageOffsetX=0
        NodeImageOffsetY=353
        NodeImageWidth=16
        NodeImageHeight=16
        NodeImageUrl="/_layouts/images/fgimg.png"
        RTLNodeImageOffsetX=0
        RTLNodeImageOffsetY=376
        RTLNodeImageWidth=16
        RTLNodeImageHeight=16
        RTLNodeImageUrl="/_layouts/images/fgimg.png"
        HideInteriorRootNodes="true"
        SkipLinkText="" />
      </asp:ContentPlaceHolder>
     </SharePoint:PopoutMenu>
    </asp:ContentPlaceHolder>

   <!-- save button at top of ribbon -->
   <SharePoint:PageStateActionButton id="PageStateActionButton" runat="server" Visible="false" /></SharePoint:SPRibbonPeripheralContent>

   <!-- ribbon right side content starts here -->
   <SharePoint:SPRibbonPeripheralContent
    runat="server"
    Location="TabRowRight"
    ID="RibbonTabRowRight"
    CssClass="s4-trc-container s4-notdlg">

    <!-- GlobalSiteLink0 delegate - the variation selector / shows nothing by default otherwise -->
    <SharePoint:DelegateControl runat="server" ID="GlobalDelegate0" ControlId="GlobalSiteLink0" />

    <!-- Welcome / Login control -->
    <div class="s4-trc-container-menu">
      <div>
      <wssuc:Welcome id="IdWelcome" runat="server" EnableViewState="false">
      </wssuc:Welcome>
      <!-- MultiLingual User Interface menu -->
      <wssuc:MUISelector ID="IdMuiSelector" runat="server"/>
     </div>
    </div>

    <!-- GlobalSiteLink2 delegate default shows nothing -->
    <SharePoint:DelegateControl ControlId="GlobalSiteLink2" ID="GlobalDelegate2" Scope="Farm" runat="server" />

    <!-- link to launch developer dashboard if its activated by admin -->
    <span>
     <span class="s4-devdashboard">
     <Sharepoint:DeveloperDashboardLauncher
      ID="DeveloperDashboardLauncher"
      NavigateUrl="javascript:ToggleDeveloperDashboard()"
      runat="server"
      ImageUrl="/_layouts/images/fgimg.png"
      Text="<%$Resources:wss,multipages_launchdevdashalt_text%>"
      OffsetX=0
      OffsetY=222
      Height=16
      Width=16 />
     </span>
    </span>
   </SharePoint:SPRibbonPeripheralContent>
   </SharePoint:SPRibbon>
  
   <!-- end main ribbon control -->
 </div>

    <!-- dynamic notification area -->
 <div id="notificationArea" class="s4-noti"></div>

    <!-- old navigation delegate? -->
 <asp:ContentPlaceHolder ID="SPNavigation" runat="server">
   <SharePoint:DelegateControl runat="server" ControlId="PublishingConsole" Id="PublishingConsoleDelegate">
     </SharePoint:DelegateControl>
 </asp:ContentPlaceHolder>

 <!-- top web part panel -->
 <div id="WebPartAdderUpdatePanelContainer">
  <asp:UpdatePanel
   ID="WebPartAdderUpdatePanel"
   UpdateMode="Conditional"
   ChildrenAsTriggers="false"
   runat="server">
   <ContentTemplate>
    <WebPartPages:WebPartAdder ID="WebPartAdder" runat="server" />
   </ContentTemplate>
   <Triggers>
    <asp:PostBackTrigger ControlID="WebPartAdder" />
   </Triggers>
  </asp:UpdatePanel>
 </div>
</div>

<!-- =====  End Ribbon and other Top Content ============================================================ -->
<asp:ContentPlaceHolder id="PlaceHolderMain" runat="server"/>
<asp:ContentPlaceHolder id="PlaceHolderFormDigest" runat="server">
 <SharePoint:FormDigest runat="server"/>
</asp:ContentPlaceHolder>

<input type="text" name="__spDummyText1" style="display:none;" size="1"/>
<input type="text" name="__spDummyText2" style="display:none;" size="1"/>

</form>
<SharePoint:WarnOnUnsupportedBrowsers runat="server"/>
</body>
</html>

I deployed the page to the masterpage gallery with the following module (elements.xml):

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="
http://schemas.microsoft.com/sharepoint/">
  <Module Name="ApplicationMaster" Url="_catalogs/masterpage">
    <File Path="ApplicationMaster\_ribbon_only.master" Url="_ribbon_only.master" IgnoreIfAlreadyExists="FALSE" Type="GhostableInLibrary" />
  </Module>
</Elements>

Application Page
The next step was to create an appication page, which is fairly straight forward, however there is a trick to get the new master page to load. The dynamic master page assignment is removed from the markup and then the new master page is assigned on page initialisation.
Markup:

<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TrendViewPage.aspx.cs" Inherits="XXXX.AppPage" DynamicMasterPageFile="~masterurl/default.master" %>

<asp:Content ID="Title" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server" style="height:100%">AppPage</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server" style="height:100%">
</asp:Content>

C# Code Behind:

using System;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Web;
using System.Collections.Generic;

namespace XXXX
{
    public partial class AppPage : LayoutsPageBase
    {

        protected void Page_PreInit(object sender, EventArgs e)
        {
            // Override master page
            this.MasterPageFile = "../../_catalogs/masterpage/_ribbon_only.master";
        }

    }
}

The master page is assigned during initialisation because custom master pages can't be dynamically assined to app pages in markup. I originally deployed the page to the _layouts folder for testing and was able to use the DynamicMasterPageFile="~masterurl/default.master" attribute in the Page element and override it in the PreInit method, however once I moved it to a library so it could be scoped at site collection level, this did not work and produced the following error :

The dynamicmasterpagefile attribute on the page directive is not allowed in this page.

Removing this attribute (as the markup shows) works fine and simply allows the master to be assigned at runtime.
The app page is deployed to a document library using the following module (elements.xml):

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="
http://schemas.microsoft.com/sharepoint/">
  <Module Name="AppPage" Url="Lists/AppPageLib">
  <File Path="AppPage\AppPage.aspx" Url="AppPage.aspx"  Type="GhostableInLibrary" IgnoreIfAlreadyExists="False" />
</Module>
</Elements>

The page should look like this (obviously you would have some content in the app page!):

No comments:

Post a Comment