ASP Calendar
This is my version of an asp calendar (as a UserControl here for simplicity). It doesn't postback - it's intended for static display only (if you need a datepicker, there are plenty of better javascript versions). The html is much simpler than the real calendar control and lends itself to css styling (each date cell has a css classes like "y2007 m01 d01" which make it easy to highlight e.g. 1st of every month, or a particular month among several calendars just with css rules). The DayRender event is exactly the same as the asp Calendar.
Code behind
using System;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
/// <summary>
/// Displays a localised Gregorian calendar. Similar to the <see cref="System.Web.UI.WebControls.Calendar"/> but with simpler markup and no selection/ postbacks. Use the <see cref="DayRender"/> event to add calendar "events".
/// </summary>
/// <remarks>
/// This is localized (month and day names, long date format) using the .Net framework.
/// <code>
/// CultureInfo culture = new CultureInfo("ja-JP");
/// System.Threading.Thread.CurrentThread.CurrentCulture = culture;
/// </code>
/// It won't do a Hebrew/he-IL or Japanese/ja-JP calendar, as DateTime always uses a Gregorian calendar (you would have to account for having 13 months).
/// </remarks>
/// <example>
/// Example css:
/// <code>
/// table { border-collapse: collapse; }
/// td { margin: 0; padding: 5px; border: 1px solid gray; text-align: right; vertical-align: top; }
/// .weekend { background-color: #bbb; }
/// .today { background-color: #ddd; }
/// </code>
/// Example use:
/// <code>
/// <uc1:Calendar ID="Calendar1" runat="server" Date="2007/01/12" WeekendCssClass="weekend" TodayCssClass="today" OnDayRender="Calendar_DayRender" FirstDayOfWeek="Sunday" />
/// </code>
/// </example>
[DefaultEvent("DayRender"), DefaultProperty("Date")]
public partial class Calendar : System.Web.UI.UserControl
{
#region Properties
public string CssClass
{
get
{
object o = ViewState["CssClass"];
return (o != null) ? (string)o : null;
}
set { ViewState["CssClass"] = value; }
}
public DateTime Date
{
get
{
object o = ViewState["Date"];
return (o != null) ? (DateTime)o : DateTime.Today;
}
set { ViewState["Date"] = value; }
}
public DayOfWeek FirstDayOfWeek
{
get
{
object o = ViewState["FirstDayOfWeek"];
return (o != null) ? (DayOfWeek)o : CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek;
}
set { ViewState["FirstDayOfWeek"] = value; }
}
public string HeaderRowCssClass
{
get
{
object o = ViewState["HeaderRowCssClass"];
return (o != null) ? (string)o : null;
}
set { ViewState["HeaderRowCssClass"] = value; }
}
public bool ShowCaption
{
get
{
object o = ViewState["ShowCaption"];
return (o != null) ? (bool)o : true;
}
set { ViewState["ShowCaption"] = value; }
}
public string TodayCssClass
{
get
{
object o = ViewState["TodayCssClass"];
return (o != null) ? (string)o : null;
}
set { ViewState["TodayCssClass"] = value; }
}
public string WeekendCssClass
{
get
{
object o = ViewState["WeekendCssClass"];
return (o != null) ? (string)o : null;
}
set { ViewState["WeekendCssClass"] = value; }
}
#endregion
#region Events
/// <summary>
/// Occurs when a day is rendered. Exactly the same as asp:Calender.
/// </summary>
/// <example>
/// <code>
///protected void Calendar_DayRender(object sender, DayRenderEventArgs e)
///{
/// if (e.Day.IsToday)
/// {
/// HtmlGenericControl para = new HtmlGenericControl("p");
/// para.InnerText = "Today";
/// e.Cell.Controls.Add(para);
/// }
///}
/// </code>
/// </example>
public event DayRenderEventHandler DayRender;
#endregion
#region Methods
protected void Page_Load(object sender, EventArgs e)
{
DrawCalendar(); //redraw for postbacks too
}
protected void DrawCalendar()
{
CultureInfo culture = CultureInfo.CurrentCulture;
int firstDay = (int)FirstDayOfWeek;
if (!string.IsNullOrEmpty(CssClass))
CalendarTable.CssClass = CssClass;
if (ShowCaption)
CalendarTable.Caption = Date.ToString(culture.DateTimeFormat.YearMonthPattern, culture);
CalendarTable.Rows.Clear(); //clear any presentation rows
DrawWeekDayHeaders(culture);
int daysInMonth = culture.Calendar.GetDaysInMonth(Date.Year, Date.Month);
DateTime firstDayOfMonth = new DateTime(Date.Year, Date.Month, 1);
int startWeekDay = (int)firstDayOfMonth.DayOfWeek;
TableRow currentRow = new TableRow();
CalendarTable.Rows.Add(currentRow);
if (firstDay != startWeekDay)
{
int dayIndex = firstDay;
int leadingDays = startWeekDay - firstDay;
if (leadingDays < 0) leadingDays = 6 - firstDay + startWeekDay + 1;
for (int i = 0; i < leadingDays; i++)
{
currentRow.Cells.Add(new TableCell());
}
}
DateTime date = firstDayOfMonth;
for (int i = 1; i <= daysInMonth; i++)
{
DrawDay(currentRow, date);
date = date.AddDays(1);
if (date.Day == daysInMonth)
break;
if (date.DayOfWeek == FirstDayOfWeek)
{
currentRow = new TableRow();
CalendarTable.Rows.Add(currentRow);
}
}
//fill rest of week
for (int i = 0; i < 6; i++)
{
if ((int)date.DayOfWeek == firstDay)
break;
TableCell cell = new TableCell();
cell.ToolTip = date.ToLongDateString();
currentRow.Cells.Add(cell);
date = date.AddDays(1);
}
}
protected void DrawDay(TableRow currentRow, DateTime date)
{
string dateString = date.ToString("dd", CultureInfo.CurrentCulture);
bool isWeekend = (date.DayOfWeek == DayOfWeek.Saturday) || (date.DayOfWeek == DayOfWeek.Sunday);
bool isToday = date.Equals(DateTime.Today);
TableCell cell = new TableCell();
string cssClass = "y" + date.Year + " m" + date.ToString("MM", CultureInfo.CurrentCulture) + " d" + dateString;
cell.CssClass = cssClass +
(isWeekend ? " " + WeekendCssClass : string.Empty)
+ (isToday ? " " + TodayCssClass : string.Empty);
Label lab = new Label();
lab.Text = dateString;
lab.ToolTip = date.ToLongDateString();
cell.Controls.Add(lab);
DayRenderEventHandler dayRender = DayRender;
if (dayRender != null)
{
var day = new CalendarDay(date,
isWeekend,
isToday,
false, //this is never selectable
false, //this is never another month
dateString);
var eventArgs = new DayRenderEventArgs(cell, day);
dayRender(this, eventArgs);
}
currentRow.Cells.Add(cell);
}
protected void DrawWeekDayHeaders(CultureInfo culture)
{
TableHeaderRow row = new TableHeaderRow();
CalendarTable.Rows.Add(row);
if (!string.IsNullOrEmpty(HeaderRowCssClass)) row.CssClass = HeaderRowCssClass;
int firstDay = (int)culture.DateTimeFormat.FirstDayOfWeek;
string[] abbreviatedDayNames = culture.DateTimeFormat.AbbreviatedDayNames;
int dayIndex = firstDay;
for (int i = 0; i < 7; i++)
{
TableHeaderCell cell = new TableHeaderCell();
row.Controls.Add(cell);
cell.Text = abbreviatedDayNames[dayIndex];
dayIndex++;
if (dayIndex > 6) dayIndex = 0;
}
}
/// <summary>
/// Renders to HTML. Use this method for Ajax postbacks.
/// </summary>
/// <returns>A string of html suitable for ajax.</returns>
public string RenderToHtml()
{
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
using (HtmlTextWriter textWriter = new HtmlTextWriter(sw))
{
this.RenderControl(textWriter);
}
}
return sb.ToString();
}
#endregion
}
Page
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Calendar.ascx.cs" Inherits="Calendar" %>
<asp:Table runat="server" ID="CalendarTable">
<asp:TableHeaderRow>
<asp:TableHeaderCell Text="M" />
<asp:TableHeaderCell Text="T" />
<asp:TableHeaderCell Text="W" />
<asp:TableHeaderCell Text="T" />
<asp:TableHeaderCell Text="F" />
<asp:TableHeaderCell Text="S" />
<asp:TableHeaderCell Text="S" />
</asp:TableHeaderRow>
<asp:TableRow>
<asp:TableCell Text=" " />
<asp:TableCell Text=" " />
<asp:TableCell Text="1" />
<asp:TableCell Text="2" />
<asp:TableCell Text="3" />
<asp:TableCell Text="4" />
<asp:TableCell Text="5" />
</asp:TableRow>
</asp:Table>