Creating SharePoint global calendar

Creating global calendar that shows data from different calendars is something that SharePoint doesn’t have out-of-box. Using site data query and calendar view control we can easily create global calendar and make it show data from lists we want.

SharePoint global calendar 

Before you start you should create two calendars to SharePoint site where you want to show global calendar. I tested my code on MOSS 2007 but it should also work on WSS 3.0. If you want to get done fast then you can create new web part and paste all these methods to web part class. Don’t forget to change list GUID-s before deploying your code.

Creating the calendar control

As a first thing let’s update CreateChildControls method. We don’t write calendar creation code here because in this method we want things to be simple and clear.


/// <summary>
///
Called by the ASP.NET page framework to notify server controls
/// that use composition-based implementation to create any child
/// controls they contain in preparation for posting back or
/// rendering.
/// </summary>
protected override void
CreateChildControls()
{
   
base
.CreateChildControls();

   
try
    {
        AddCalendar();
    }
   
catch (Exception
ex)
    {
        Controls.Add(
new LiteralControl("<b>Error</b> "
));
        Controls.Add(
new LiteralControl(ex.ToString()));
    }

}

As a next thing let’s add code for AddCalendar method. In this method we control the process of calendar creation. We need reference to current web and then we play with data. GetQueryData returns us DataTable and GetCalendarItems converts this DataTable to SPCalendarItemCollection. Then we detect calendar view type (day view, week view,  month view) by request variables and as a last thing we bind data to calendar and add calendar to web part controls collection.


/// <summary>
///
Adds the calendar to web part.
/// </summary>
private void
AddCalendar()
{
   
var web = SPContext
.Current.Web;
   
var
results = GetQueryData(web);
   
var
items = GetCalendarItems(web, results);

   
var calView = new SPCalendarView
();
    calView.ViewType = GetCalendarType(
Page.Request["CalendarPeriod"]);
    calView.DataSource = items;
    calView.DataBind();
    Controls.Add(calView);
}

Quering lists

Now let’s ask data for calendar. We have to create SPSiteDataQuery that is able to query all the lists in site or site collection. This is a little bit tricky class and you can read about it blog posting SPSiteDataQuery Samples for WSS v3 from thekid.me.uk blog. We will write now our GetQueryData method that creates site data query and returns results. We are able to get these results only as DataTable. Why separate method? Just look at this method – it is pretty long.


/// <summary>
///
Executes the query against the web and returns
/// results as DataTable.
/// 
</summary>
///
 <param name="web">The web that is queried.
</param>
///
 <returns>Query results as DataTable.</returns>
private DataTable GetQueryData(SPWeb
web)
{
   
var query = new SPSiteDataQuery
();

    query.Lists =
@"<Lists>
                        <List ID='{56F5E040-D547-4BF5-8C99-F019D54F9997}' />
                        <List ID='{92A87CB9-E39B-4C2D-B37D-5721E6C7FECD}' />
                    </Lists>"
;

    query.Query =
@"<Where>
                <Gt>
                    <FieldRef Name='ID' />
                    <Value Type='Number'>0</Value>
                </Gt>
            </Where>"
;

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

    query.ViewFields =
"<FieldRef Name='Title' />"
;
    query.ViewFields +=
"<FieldRef Name='ID' />"
;
    query.ViewFields +=
"<FieldRef Name='EventDate' />"
;
    query.ViewFields +=
"<FieldRef Name='EndDate' />"
;
    query.ViewFields +=
"<FieldRef Name='Location' />"
;
    query.ViewFields +=
"<FieldRef Name='Description' />"
;
    query.ViewFields +=
"<FieldRef Name='fRecurrence' />"
;

    query.RowLimit = 100;

   
return web.GetSiteData(query);
}

NB! The first block of XML is lists definition. Replace GUID-s of lists with GUID-s of your lists! Also don’t remove row limit. You can change the value but if you remove it then you get no results.

Transforming results

GetSiteData returns results as DataTable. SPCalendarView accepts DataTable as data source but it shows calendar empty. We need SPCalendarItemCollection to get results to calendar. For this conversion we write the method GetCalendarItems. This method takes DataTable returned by GetSiteData and returns results as SPCalendarItemCollection.

The code for calendar actions is borrowed from Tom Stegeman blog posting Using SPCalendarView to show items in a calendar.


/// <summary>
///
Gets the collection of calendar items based on site
/// data query results.
/// 
</summary>
///
 <param name="web">The web that was queried.
</param>
///
 <param name="results">The results of query.
</param>
///
 <returns>Collection of calendar items accepted by
/// calendar component</returns>
private SPCalendarItemCollection GetCalendarItems(SPWeb web, DataTable
results)
{
   
var items = new SPCalendarItemCollection
();
   
foreach (DataRow row in
results.Rows)
    {
       
var listGuid = new Guid(row["ListId"] as string
);
       
var
list = web.Lists[listGuid];

       
SPCalendarItem item = new SPCalendarItem
();

       
foreach (SPForm form in
list.Forms)
           
if
(form.Type == PAGETYPE.PAGE_DISPLAYFORM)
            {
                item.DisplayFormUrl = form.ServerRelativeUrl;
               
break
;
            }

        item.ItemID = row[
"ID"] as string
;
        item.StartDate = DateTime.Parse(row[
"EventDate"] as string
);
        item.EndDate = DateTime.Parse(row[
"EndDate"] as string
);
        item.hasEndDate =
true
;
        item.Title = row[
"Title"] as string
;
        item.Location = row[
"Location"] as string
;
        item.Description = row[
"Description"] as string
;
        item.IsAllDayEvent = (
int.Parse(row["fAllDayEvent"] as string
) != 0);
        item.IsRecurrence = (
int.Parse(row["fRecurrence"] as string
) != 0);
        item.CalendarType =
Convert
.ToInt32(SPCalendarType.Gregorian);
        items.Add(item);
    }

   
return items;
}

This method has one little trick. We need URL template to assign it to DisplayFormUrl. When calendar is rendered then parameter ID will be added to this URL.

Why we don’t ask it from list and then use it as constant? Okay, results are coming from more than one list. Each list has separate display form and therefore separate display form URL. To get correct URL-is it is good idea to ask them directly from list Forms collection.

Detecting calendar type

As a last thing we have to add one utility method to our web part class. We need to know what view calendar has to show. There three views:

  • day view,
  • week view,
  • month view.

When we switch view then view type is given to calendar over query string. As query string is something that everybody can easily change we need to make sure that we assign correct view type to calendar. Otherwise exception will be thrown.


/// <summary>
///
Gets the type of the calendar view.
/// 
</summary>
///
 <param name="type">The type to be checked.
</param>
///
 <returns>Correct view type of calendar.</returns>
private static string GetCalendarType(string
type)
{
   
if (type == null
)
        type =
string
.Empty;

   
switch
(type.ToLower())
    {
       
case "day"
:
           
return "day"
;
       
case "week"
:
           
return "week"
;
       
case "timeline"
:
           
return "timeline"
;
       
default
:
           
return "month";
    }
}

How it’s time to compile the code and deploy it to server. If you or I have make no mistakes in code then you should see familiar SharePoint calendar that shows results from more than one calendar.

SharePoint global calendar

You can click on image to see how it looks full size. Training info comes from list Calendar and meeting information comes from Rooms Calendar.

Happy SharePointing!


2 thoughts on “Creating SharePoint global calendar

Leave a Reply

Your email address will not be published. Required fields are marked *