How to use a publishing page as display form

A client wanted to place a SharePoint calendar on a publishing page and have it configured such that when you clicked an event the full details showed up at the top of the page, and searching for calendar items should also put you at this page.

Sounds easy just put the calendar view on the page and set the calendars display form to be that page. But setting the display form to be the publishing page puts the ID of the calendar item in the URL of the publishing page which then confuses SharePoint as it thinks it has to lookup that id in the Pages list.

The solution is to introduce a page as display form which the redirects back but with the ID of the calendar item as a querystring parameter with another name than id. Then we have to look up the right instance of the calendar item in case of recurrence (but that’s the topic of the next post).

I use my redirect application page for both setting up and doing the redirection. For setup it just contains a dropdown list with all calendars on the site and a textbox for entering the URL of the page to where we should redirect.

I save the redirect target of each calendar in the properties bag of the site.

Here is the code behind for reference:

using System;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
 
namespace Kraftvaerk.CustomApplicationPages
{
    public class CalendarItemRedirect : LayoutsPageBase
    {
        protected DropDownList lbCalendar;
        protected TextBox tbTargetUrl;
 
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (!IsPostBack)
            {
                PerformRedirect();
 
                // If we arrive here we didn't perform the redirect
                // which means that we want the editing page
                //
                SPWeb web = SPContext.Current.Web;
                foreach (SPList list in web.Lists)
                {
                    if (list.BaseTemplate != SPListTemplateType.Events)
                        continue;
                    ListItem li=new ListItem(list.Title, list.ID.ToString());
                    lbCalendar.Items.Add(li);
                }
                if (lbCalendar.Items.Count < 0)
                {
                    OnCalendarChanged(null, e);
                }
            }
        }
 
        private void PerformRedirect()
        {
            if (Request.QueryString["List"] == null)
                return;
 
            SPListItem item = SPContext.Current.ListItem;
            SPWeb web = SPContext.Current.Web;
            string propertyKey = String.Format("CalendarItemRedirect:{0}", Request.QueryString["List"]);
            string url=String.Format("{0}/{1}", web.Url, (string)web.Properties[propertyKey]);
            url = url.Replace("{Date}", ((DateTime)item[SPBuiltInFieldId.StartDate]).Date.ToShortDateString());
            url = url.Replace("{RecurrenceId}", item.RecurrenceID);
            Response.Redirect(url, true);
        }
 
        protected void OnCalendarChanged(object sender, EventArgs e)
        {
            SPWeb web = SPContext.Current.Web;
            string propertyKey = String.Format("CalendarItemRedirect:{0}", lbCalendar.SelectedValue);
            if (web.Properties.ContainsKey(propertyKey))
                tbTargetUrl.Text = (string)web.Properties[propertyKey];
            else
                tbTargetUrl.Text = "";
        }
 
        protected void OnSave(object sender, EventArgs e)
        {
            SPWeb web = SPContext.Current.Web;
            string propertyKey = String.Format("CalendarItemRedirect:{0}", lbCalendar.SelectedValue);
            web.Properties[propertyKey] = tbTargetUrl.Text;
            web.Properties.Update();
            SPList list = web.Lists[new Guid(lbCalendar.SelectedValue)];
            string displayFormUrl = null;
            if (String.IsNullOrEmpty(tbTargetUrl.Text))
            {
                // Set the DisplayFormUrl to default
                // We can't set it to blank for some obscure reason
                // so set it to the displayForm of the list.
                //
                displayFormUrl = list.Forms[PAGETYPE.PAGE_DISPLAYFORM].Url;
            }
            else
            {
                // Set this page as DisplayFormUrl
                // We will then redirect to the right one with
                // tokens filled out
                //
                displayFormUrl = this.Page.AppRelativeVirtualPath;
                if (displayFormUrl.StartsWith("~/"))
                    displayFormUrl = displayFormUrl.Substring(2);
            }
            foreach (SPContentType ct in list.ContentTypes)
            {
                ct.DisplayFormUrl = displayFormUrl;
                ct.Update();
            }
        }
 
        protected override bool AllowAnonymousAccess
        {
            get
            {
                return true;
            }
        }
 
        protected override bool RequireSiteAdministrator
        {
            get
            {
                return false;
            }
        }
 
    }
}
comments powered by Disqus