Monday, May 05, 2008

Creating a Custom SharePoint (MOSS) 2007 Calendar View Web Part with VS.NET 2005

This conceptual tutorial shows you how to create a custom calendar web part that gets its events from an already-existing calendar in MOSS 2007.

Prerequisites:

Note: This tutorial will be a conceptual one, not one where I go into the actual development of a real application/web part.

  1. Open up VS.NET, then create a new SharePoint-Web Part project.
  2. Make sure a reference to Microsoft.SharePoint.dll is there.
  3. Open up the Web Part .cs (code) file.
  4. Ensure the following using statements are present:
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebControls;
    using Microsoft.SharePoint.WebPartPages;
  5. Ensure the Web Part class is deriving from the following class:
    System.Web.UI.WebControls.WebParts.WebPart
  6. Something in the Web Part class code file, define variables that might be used, such as the following: private String strListName = "DotNetFun Calendar"; private SPCalendarView calendarView = new SPCalendarView(); private Guid listGuid;
  7. Override the base class' CreateChildControls() method:
    protected override void CreateChildControls()
  8. The CreateChildControls() method should look something like this: protected override void CreateChildControls() { try { SPSecurity.RunWithElevatedPrivileges( delegate() { base.CreateChildControls(); ViewType viewType = ViewType.Month; using (SPWeb web = SPContext.Current.Site.OpenWeb(this.webGuid)) { // Change Cal-view based on if QueryString specifies it: if (Page.Request.QueryString["CalendarPeriod"] != null) { switch (Page.Request.QueryString["CalendarPeriod"].ToString().ToLower()) { case "day": this.calendarView.ViewType = "day"; viewType = ViewType.Day; break; case "week": this.calendarView.ViewType = "week"; viewType = ViewType.Week; break; case "timeline": this.calendarView.ViewType = "timeline"; viewType = ViewType.Timeline; break; default: this.calendarView.ViewType = "month"; viewType = ViewType.Month; break; } } SPList listDotNetFunCalendar = web.Lists[this.strListName]; if (listDotNetFunCalendar.Views["Calendar"] == null) throw new ApplicationException("The Calendar view was not found. Please create one accordingly."); SPView viewDotNetFunCalendar = listDotNetFunCalendar.Views["Calendar"]; if (this.calendarView.ViewGuid != null) viewDotNetFunCalendar = listDotNetFunCalendar.Views[new Guid(this.calendarView.ViewGuid)]; this.listGuid = listDotNetFunCalendar.ID; DateTime dtStart = DateTime.Now; if (this.calendarView.SelectedDate != null) dtStart = DateTime.Parse(this.calendarView.SelectedDate).AddDays(-7); DateTime dtEnd = dtStart.AddMonths(1).AddDays(7); SPQuery query = new SPQuery(); query.Query = String.Format( "<Query>" + "<Where><And>" + "<Geq><FieldRef Name=\"{0}\" />" + "<Value Type=\"DateTime\">{1}</Value></Geq>" + "<Leq><FieldRef Name=\"{0}\" />" + "<Value Type=\"DateTime\">{2}</Value></Leq>" + "</And></Where><OrderBy><FieldRef Name=\"{0}\" /></OrderBy>" + "</Query>", "Start Time", dtStart.ToShortDateString(), dtEnd.ToShortDateString()); viewDotNetFunCalendar.Query = query.Query; web.AllowUnsafeUpdates = true; //viewDotNetFunCalendar.Update(); //System.Web.HttpContext.Current.Response.Write(String.Format("{0}<br />", viewDotNetFunCalendar.Query)); SPCalendarItemCollection items = new SPCalendarItemCollection(); foreach (SPListItem listItem in listDotNetFunCalendar.GetItems(viewDotNetFunCalendar)) { SPCalendarItem calItem = new SPCalendarItem(); calItem.ItemID = listItem["ID"].ToString(); calItem.Title = listItem["Title"].ToString(); calItem.CalendarType = Convert.ToInt32(SPCalendarType.Gregorian); calItem.StartDate = (DateTime)listItem["Start Time"]; calItem.ItemID = listItem.ID.ToString(); calItem.WorkSpaceLink = String.Format("/Lists/{0}/DispForm.aspx", this.strListName); // Only allow color-coding, which requires all all-day // event, if a Month view: if (viewType == ViewType.Month) calItem.IsAllDayEvent = true; calItem.DisplayFormUrl = String.Format("/Lists/{0}/DispForm.aspx", this.strListName); if (listItem["End Time"] != null) { calItem.hasEndDate = true; calItem.EndDate = (DateTime)listItem["End Time"]; } else calItem.hasEndDate = false; if (listItem["Description"] != null) calItem.Description = listItem["Description"].ToString(); if (listItem["Location"] != null) calItem.Location = listItem["Location"].ToString(); // Define CSS based on category: // Note, CSS styles are stored in CORE.CSS, here: // %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\1033\STYLES // Append "sel" (without quotes) to the CSS Class name to // override the onmouseover CSS changes in the CORE.CSS file. switch (listItem["Category"].ToString()) { case "Programming/Scheduling": calItem.BackgroundColorClassName = "DotNetFunCalendarProgramming"; break; case "Production": calItem.BackgroundColorClassName = "DotNetFunCalendarProduction"; break; case "Ad Sales": calItem.BackgroundColorClassName = "DotNetFunCalendarAdSales"; break; case "Marketing/Promotions": calItem.BackgroundColorClassName = "DotNetFunCalendarMarketing"; break; case "PR": calItem.BackgroundColorClassName = "DotNetFunCalendarPR"; break; case "Online/Interactive": calItem.BackgroundColorClassName = "DotNetFunCalendarInteractive"; break; case "Company Events/HR": calItem.BackgroundColorClassName = "DotNetFunCalendarHR"; break; case "General": calItem.BackgroundColorClassName = "DotNetFunCalendarGeneral"; break; } items.Add(calItem); } // Set calendar-only properties: this.calendarView.DisplayItemFormUrl = String.Format("/Lists/{0}/DispForm.aspx", this.strListName); this.calendarView.EditItemFormUrl = String.Format("/Lists/{0}/EditForm.aspx", this.strListName); this.calendarView.NewItemFormUrl = String.Format("/Lists/{0}/NewForm.aspx", this.strListName); this.calendarView.EnableViewState = true; this.calendarView.DataSource = items; this.calendarView.DataBind(); this.DataBind(); } this.Controls.Add(this.calendarView); }); } catch (Exception err) { this.HandleException(err); } }
  9. Override the base class' RenderContents(HtmlTextWriter writer) method:
    RenderContents(HtmlTextWriter writer)
  10. The RenderContents(HtmlTextWriter writer) method should look something like this: protected override void RenderContents(HtmlTextWriter writer) { SPSecurity.RunWithElevatedPrivileges( delegate() { // Check if current user can add events: bool blnCanAddEvents = false; using (SPWeb web = SPContext.Current.Site.OpenWeb(this.webGuid)) { try { web.Lists[this.strListName].Permissions.CheckPermissions(SPRights.AddListItems); blnCanAddEvents = true; } catch { } } // Render header firstly: StringBuilder sbHeader = new StringBuilder(); sbHeader.AppendLine("<table bgcolor='#05C4D8' align='center' width='100%' border='1' cellpadding='2' cellspacing='2'>"); sbHeader.AppendLine("<tr><th align='center' bgcolor='Black'>"); sbHeader.AppendLine("<font color='#05C4D8' size='4'>DotNetFun PROGRAMMING</font>"); sbHeader.AppendLine("</th></table>"); writer.Write(sbHeader.ToString()); // Render calendar secondly: this.calendarView.RenderControl(writer); // Append color legend: StringBuilder sbLegend = new StringBuilder(); sbLegend.AppendLine("<table align='center' width='100%' border='0'>"); sbLegend.AppendLine("<td width='50%' align='left' valign='top'>"); sbLegend.AppendLine("<b><u>Legend:</u></b><br /><br />"); sbLegend.AppendLine("<label style='width:250px;background-color:#72FFF6;padding:2px;'>Programming/Scheduling</label><br />"); sbLegend.AppendLine("<label style='width:250px;background-color:#1AA4C2;padding:2px;'>Production</label><br />"); sbLegend.AppendLine("<label style='width:250px;background-color:#3F8698;padding:2px;'>Ad Sales</label><br />"); sbLegend.AppendLine("<label style='width:250px;background-color:#76D600;padding:2px;'>Marketing/Promotions</label><br />"); sbLegend.AppendLine("<label style='width:250px;background-color:#FF9A00;padding:2px;'>PR</label><br />"); sbLegend.AppendLine("<label style='width:250px;background-color:#E000B6;padding:2px;'>Online/Interactive</label><br />"); sbLegend.AppendLine("<label style='width:250px;background-color:#F51604;padding:2px;'>Company Events/HR</label><br />"); sbLegend.AppendLine("<label style='width:250px;background-color:White;padding:2px;'>General</label><br />"); sbLegend.AppendLine("</td>"); sbLegend.AppendLine("<td width='50%' align='left' valign='top'>"); sbLegend.AppendLine("<b><u>Options:</u></b><br /><br />"); if (blnCanAddEvents) sbLegend.AppendLine(String.Format("<li><a href=\"/Lists/{0}/NewForm.aspx\">Add New Event</a></li>", this.strListName)); sbLegend.AppendLine(String.Format("<li><a href=\"/Lists/{0}/\">View the Full Calendar</a></li>", this.strListName)); sbLegend.AppendLine(String.Format("<li><a href=\"/_layouts/listfeed.aspx?List={0}\">RSS Feed</a></li>", this.listGuid.ToString())); sbLegend.AppendLine(String.Format("<li><a href=\"http://DotNetFunshare001/_layouts/SubNew.aspx?List={0}\">Alert Me When this Calendar Changes</a></li>", this.listGuid.ToString())); sbLegend.AppendLine("</td></table>"); writer.Write(sbLegend.ToString()); }); }
  11. Ensure that the AssemblyInfo.cs file is using whole, major version numbers and nothing else (e.g., 1.0.0.0).
  12. The code sample in this tutorial makes use of CSS via the MOSS 2007's CORE.CSS master CSS file, located here: %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\1033\STYLES
  13. Before you can use the Web Part, it must be trusted by declaring it a safe control. Do this by adding something like the following to the site's web.config file, typically, located here, C:\Inetpub\wwwroot\wss\VirtualDirectories\80\web.config:
  14. <SafeControl Assembly="SPDotNetFunCalendarWebpart, Version=52.0.0.0, Culture=neutral, PublicKeyToken=fc6dbd48e3fd5742" Namespace="DotNetFun.SharePoint.WebParts" TypeName="*" />
  15. Add the following line to the AssemblyInfo.cs code file: [assembly: System.Security.AllowPartiallyTrustedCallers()]
  16. Sign the project with a strong-name key, then add it to the GAC, after compiling it, of course.
  17. Go to the settings page of the site on which the calendar list exists and from which data is being retrieved.
  18. Under the Galleries section, click on Web Parts.
  19. Click on the New button.
  20. Check the checkbox for the calendar web part just created.
  21. Click on Populate Gallery.
  22. Add a new Permission Level for this particular type of web part, as shown above, and grant it basic rights plus the Add right, as without Add, it won't work.
  23. The web part is now ready for use on this site.

Sample, entire Web part class code file:

using System; using System.Runtime.InteropServices; using System.Web.UI; using System.Web.UI.WebControls.WebParts; using System.Xml.Serialization; using Microsoft.SharePoint; using Microsoft.SharePoint.WebControls; using Microsoft.SharePoint.WebPartPages; using System.Text; namespace DotNetFun.SharePoint.WebParts { [Guid("a6b6f461-cc95-4cf3-b419-b0b1b1d20355")] public class SPDotNetFunCalendarWebpart : System.Web.UI.WebControls.WebParts.WebPart { private Guid webGuid = SPContext.Current.Web.ID; private String strListName = "DotNetFun Calendar"; private SPCalendarView calendarView = new SPCalendarView(); private Guid listGuid; public SPDotNetFunCalendarWebpart() { this.ExportMode = WebPartExportMode.All; this.Title = "DotNetFun Programming Calendar"; } protected override void RenderContents(HtmlTextWriter writer) { SPSecurity.RunWithElevatedPrivileges( delegate() { // Check if current user can add events: bool blnCanAddEvents = false; using (SPWeb web = SPContext.Current.Site.OpenWeb(this.webGuid)) { try { web.Lists[this.strListName].Permissions.CheckPermissions(SPRights.AddListItems); blnCanAddEvents = true; } catch { } } // Render header firstly: StringBuilder sbHeader = new StringBuilder(); sbHeader.AppendLine("<table bgcolor='#05C4D8' align='center' width='100%' border='1' cellpadding='2' cellspacing='2'>"); sbHeader.AppendLine("<tr><th align='center' bgcolor='Black'>"); sbHeader.AppendLine("<font color='#05C4D8' size='4'>DotNetFun PROGRAMMING</font>"); sbHeader.AppendLine("</th></table>"); writer.Write(sbHeader.ToString()); // Render calendar secondly: this.calendarView.RenderControl(writer); // Append color legend: StringBuilder sbLegend = new StringBuilder(); sbLegend.AppendLine("<table align='center' width='100%' border='0'>"); sbLegend.AppendLine("<td width='50%' align='left' valign='top'>"); sbLegend.AppendLine("<b><u>Legend:</u></b><br /><br />"); sbLegend.AppendLine("<label style='width:250px;background-color:#72FFF6;padding:2px;'>Programming/Scheduling</label><br />"); sbLegend.AppendLine("<label style='width:250px;background-color:#1AA4C2;padding:2px;'>Production</label><br />"); sbLegend.AppendLine("<label style='width:250px;background-color:#3F8698;padding:2px;'>Ad Sales</label><br />"); sbLegend.AppendLine("<label style='width:250px;background-color:#76D600;padding:2px;'>Marketing/Promotions</label><br />"); sbLegend.AppendLine("<label style='width:250px;background-color:#FF9A00;padding:2px;'>PR</label><br />"); sbLegend.AppendLine("<label style='width:250px;background-color:#E000B6;padding:2px;'>Online/Interactive</label><br />"); sbLegend.AppendLine("<label style='width:250px;background-color:#F51604;padding:2px;'>Company Events/HR</label><br />"); sbLegend.AppendLine("<label style='width:250px;background-color:White;padding:2px;'>General</label><br />"); sbLegend.AppendLine("</td>"); sbLegend.AppendLine("<td width='50%' align='left' valign='top'>"); sbLegend.AppendLine("<b><u>Options:</u></b><br /><br />"); if (blnCanAddEvents) sbLegend.AppendLine(String.Format("<li><a href=\"/Lists/{0}/NewForm.aspx\">Add New Event</a></li>", this.strListName)); sbLegend.AppendLine(String.Format("<li><a href=\"/Lists/{0}/\">View the Full Calendar</a></li>", this.strListName)); sbLegend.AppendLine(String.Format("<li><a href=\"/_layouts/listfeed.aspx?List={0}\">RSS Feed</a></li>", this.listGuid.ToString())); sbLegend.AppendLine(String.Format("<li><a href=\"http://DotNetFunshare001/_layouts/SubNew.aspx?List={0}\">Alert Me When this Calendar Changes</a></li>", this.listGuid.ToString())); sbLegend.AppendLine("</td></table>"); writer.Write(sbLegend.ToString()); }); } private void HandleException(Exception Error) { SPSecurity.RunWithElevatedPrivileges( delegate() { throw Error; //System.Web.HttpContext.Current.Response.Write("<p><b><font color='red'>An error occurred: " + // Error.Message + " " + (Error.StackTrace != null ? Error.StackTrace : "") + // "</font></b></p>"); }); } protected override void OnInit(EventArgs e) { base.OnInit(e); } private enum ViewType { Day, Week, Month, Timeline } protected override void CreateChildControls() { try { SPSecurity.RunWithElevatedPrivileges( delegate() { base.CreateChildControls(); ViewType viewType = ViewType.Month; using (SPWeb web = SPContext.Current.Site.OpenWeb(this.webGuid)) { // Change Cal-view based on if QueryString specifies it: if (Page.Request.QueryString["CalendarPeriod"] != null) { switch (Page.Request.QueryString["CalendarPeriod"].ToString().ToLower()) { case "day": this.calendarView.ViewType = "day"; viewType = ViewType.Day; break; case "week": this.calendarView.ViewType = "week"; viewType = ViewType.Week; break; case "timeline": this.calendarView.ViewType = "timeline"; viewType = ViewType.Timeline; break; default: this.calendarView.ViewType = "month"; viewType = ViewType.Month; break; } } SPList listDotNetFunCalendar = web.Lists[this.strListName]; if (listDotNetFunCalendar.Views["Calendar"] == null) throw new ApplicationException("The Calendar view was not found. Please create one accordingly."); SPView viewDotNetFunCalendar = listDotNetFunCalendar.Views["Calendar"]; if (this.calendarView.ViewGuid != null) viewDotNetFunCalendar = listDotNetFunCalendar.Views[new Guid(this.calendarView.ViewGuid)]; this.listGuid = listDotNetFunCalendar.ID; DateTime dtStart = DateTime.Now; if (this.calendarView.SelectedDate != null) dtStart = DateTime.Parse(this.calendarView.SelectedDate).AddDays(-7); DateTime dtEnd = dtStart.AddMonths(1).AddDays(7); SPQuery query = new SPQuery(); query.Query = String.Format( "<Query>" + "<Where><And>" + "<Geq><FieldRef Name=\"{0}\" />" + "<Value Type=\"DateTime\">{1}</Value></Geq>" + "<Leq><FieldRef Name=\"{0}\" />" + "<Value Type=\"DateTime\">{2}</Value></Leq>" + "</And></Where><OrderBy><FieldRef Name=\"{0}\" /></OrderBy>" + "</Query>", "Start Time", dtStart.ToShortDateString(), dtEnd.ToShortDateString()); viewDotNetFunCalendar.Query = query.Query; web.AllowUnsafeUpdates = true; //viewDotNetFunCalendar.Update(); //System.Web.HttpContext.Current.Response.Write(String.Format("{0}<br />", viewDotNetFunCalendar.Query)); SPCalendarItemCollection items = new SPCalendarItemCollection(); foreach (SPListItem listItem in listDotNetFunCalendar.GetItems(viewDotNetFunCalendar)) { SPCalendarItem calItem = new SPCalendarItem(); calItem.ItemID = listItem["ID"].ToString(); calItem.Title = listItem["Title"].ToString(); calItem.CalendarType = Convert.ToInt32(SPCalendarType.Gregorian); calItem.StartDate = (DateTime)listItem["Start Time"]; calItem.ItemID = listItem.ID.ToString(); calItem.WorkSpaceLink = String.Format("/Lists/{0}/DispForm.aspx", this.strListName); // Only allow color-coding, which requires all all-day // event, if a Month view: if (viewType == ViewType.Month) calItem.IsAllDayEvent = true; calItem.DisplayFormUrl = String.Format("/Lists/{0}/DispForm.aspx", this.strListName); if (listItem["End Time"] != null) { calItem.hasEndDate = true; calItem.EndDate = (DateTime)listItem["End Time"]; } else calItem.hasEndDate = false; if (listItem["Description"] != null) calItem.Description = listItem["Description"].ToString(); if (listItem["Location"] != null) calItem.Location = listItem["Location"].ToString(); // Define CSS based on category: // Note, CSS styles are stored in CORE.CSS, here: // %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\1033\STYLES // Append "sel" (without quotes) to the CSS Class name to // override the onmouseover CSS changes in the CORE.CSS file. switch (listItem["Category"].ToString()) { case "Programming/Scheduling": calItem.BackgroundColorClassName = "DotNetFunCalendarProgramming"; break; case "Production": calItem.BackgroundColorClassName = "DotNetFunCalendarProduction"; break; case "Ad Sales": calItem.BackgroundColorClassName = "DotNetFunCalendarAdSales"; break; case "Marketing/Promotions": calItem.BackgroundColorClassName = "DotNetFunCalendarMarketing"; break; case "PR": calItem.BackgroundColorClassName = "DotNetFunCalendarPR"; break; case "Online/Interactive": calItem.BackgroundColorClassName = "DotNetFunCalendarInteractive"; break; case "Company Events/HR": calItem.BackgroundColorClassName = "DotNetFunCalendarHR"; break; case "General": calItem.BackgroundColorClassName = "DotNetFunCalendarGeneral"; break; } items.Add(calItem); } // Set calendar-only properties: this.calendarView.DisplayItemFormUrl = String.Format("/Lists/{0}/DispForm.aspx", this.strListName); this.calendarView.EditItemFormUrl = String.Format("/Lists/{0}/EditForm.aspx", this.strListName); this.calendarView.NewItemFormUrl = String.Format("/Lists/{0}/NewForm.aspx", this.strListName); this.calendarView.EnableViewState = true; this.calendarView.DataSource = items; this.calendarView.DataBind(); this.DataBind(); } this.Controls.Add(this.calendarView); }); } catch (Exception err) { this.HandleException(err); } } } }

4 comments:

routme said...

I don't know if you had this problem or not.. But BackgroundColorClassName only works if you have IsAllDayEvent set to true. If set to false, it will not change at all.

avs270 said...

How do I add the Full toolbar to the SPCalendarView?

Thanks,

Alberto da Silva

Anonymous said...

I am using this code but it is not displaying any event on the calebdar. Please Help me

Android app developers said...

I like your blog application.This is one of the Important post.I like your blog clarity.This is one of the nice post.